From 6b052feaa4c117e9ad99bf0e739310c501285e05 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 2 Sep 2021 03:29:53 -0700 Subject: [PATCH 01/34] Switch record to use python 3 f-strings --- octodns/record/__init__.py | 275 ++++++++++++++++--------------------- octodns/record/geo.py | 13 +- 2 files changed, 122 insertions(+), 166 deletions(-) diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index a8dd834..d6fc1d4 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -41,7 +41,7 @@ class Create(Change): def __repr__(self, leader=''): source = self.new.source.id if self.new.source else '' - return 'Create {} ({})'.format(self.new, source) + return f'Create {self.new} ({source})' class Update(Change): @@ -52,9 +52,8 @@ class Update(Change): # do nothing def __repr__(self, leader=''): source = self.new.source.id if self.new.source else '' - return 'Update\n{leader} {existing} ->\n{leader} {new} ({src})' \ - .format(existing=self.existing, new=self.new, leader=leader, - src=source) + return f'Update\n{leader} {self.existing} ->\n' \ + f'{leader} {self.new} ({source})' class Delete(Change): @@ -63,14 +62,15 @@ class Delete(Change): super(Delete, self).__init__(existing, None) def __repr__(self, leader=''): - return 'Delete {}'.format(self.existing) + return f'Delete {self.existing}' class ValidationError(Exception): @classmethod def build_message(cls, fqdn, reasons): - return 'Invalid record {}\n - {}'.format(fqdn, '\n - '.join(reasons)) + reasons = '\n - '.join(reasons) + return f'Invalid record {fqdn}\n - {reasons}' def __init__(self, fqdn, reasons): super(Exception, self).__init__(self.build_message(fqdn, reasons)) @@ -84,11 +84,11 @@ class Record(EqualityTupleMixin): @classmethod def new(cls, zone, name, data, source=None, lenient=False): name = text_type(name) - fqdn = '{}.{}'.format(name, zone.name) if name else zone.name + fqdn = f'{name}.{zone.name}' if name else zone.name try: _type = data['type'] except KeyError: - raise Exception('Invalid record {}, missing type'.format(fqdn)) + raise Exception(f'Invalid record {fqdn}, missing type') try: _class = { 'A': ARecord, @@ -109,7 +109,7 @@ class Record(EqualityTupleMixin): 'URLFWD': UrlfwdRecord, }[_type] except KeyError: - raise Exception('Unknown record type: "{}"'.format(_type)) + raise Exception(f'Unknown record type: "{_type}"') reasons = _class.validate(name, fqdn, data) try: lenient |= data['octodns']['lenient'] @@ -127,13 +127,13 @@ class Record(EqualityTupleMixin): reasons = [] n = len(fqdn) if n > 253: - reasons.append('invalid fqdn, "{}" is too long at {} chars, max ' - 'is 253'.format(fqdn, n)) + reasons.append(f'invalid fqdn, "{fqdn}" is too long at {n} ' + 'chars, max is 253') for label in name.split('.'): n = len(label) if n > 63: - reasons.append('invalid label, "{}" is too long at {} chars, ' - 'max is 63'.format(label, n)) + reasons.append(f'invalid label, "{label}" is too long at {n}' + ' chars, max is 63') try: ttl = int(data['ttl']) if ttl < 0: @@ -169,7 +169,7 @@ class Record(EqualityTupleMixin): @property def fqdn(self): if self.name: - return '{}.{}'.format(self.name, self.zone.name) + return f'{self.name}.{self.zone.name}' return self.zone.name @property @@ -236,7 +236,7 @@ class Record(EqualityTupleMixin): # is useful when computing diffs/changes. def __hash__(self): - return '{}:{}'.format(self.name, self._type).__hash__() + return f'{self.name}:{self._type}'.__hash__() def _equality_tuple(self): return (self.name, self._type) @@ -255,7 +255,7 @@ class GeoValue(EqualityTupleMixin): reasons = [] match = cls.geo_re.match(code) if not match: - reasons.append('invalid geo "{}"'.format(code)) + reasons.append(f'invalid geo "{code}"') return reasons def __init__(self, geo, values): @@ -278,9 +278,8 @@ class GeoValue(EqualityTupleMixin): self.values) def __repr__(self): - return "'Geo {} {} {} {}'".format(self.continent_code, - self.country_code, - self.subdivision_code, self.values) + return f"'Geo {self.continent_code} {self.country_code} " \ + "{self.subdivision_code} {self.values}'" class _ValuesMixin(object): @@ -324,11 +323,9 @@ class _ValuesMixin(object): return ret def __repr__(self): - values = "['{}']".format("', '".join([text_type(v) - for v in self.values])) - return '<{} {} {}, {}, {}>'.format(self.__class__.__name__, - self._type, self.ttl, - self.fqdn, values) + values = "', '".join([text_type(v) for v in self.values]) + klass = self.__class__.__name__ + return f"<{klass} {self._type} {self.ttl}, {self.fqdn}, ['{values}']>" class _GeoMixin(_ValuesMixin): @@ -376,10 +373,9 @@ class _GeoMixin(_ValuesMixin): def __repr__(self): if self.geo: - return '<{} {} {}, {}, {}, {}>'.format(self.__class__.__name__, - self._type, self.ttl, - self.fqdn, self.values, - self.geo) + klass = self.__class__.__name__ + return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, ' \ + f'{self.values}, {self.geo}>' return super(_GeoMixin, self).__repr__() @@ -408,9 +404,8 @@ class _ValueMixin(object): return ret def __repr__(self): - return '<{} {} {}, {}, {}>'.format(self.__class__.__name__, - self._type, self.ttl, - self.fqdn, self.value) + klass = self.__class__.__name__ + return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, {self.value}>' class _DynamicPool(object): @@ -454,7 +449,7 @@ class _DynamicPool(object): return not self.__eq__(other) def __repr__(self): - return '{}'.format(self.data) + return f'{self.data}' class _DynamicRule(object): @@ -484,7 +479,7 @@ class _DynamicRule(object): return not self.__eq__(other) def __repr__(self): - return '{}'.format(self.data) + return f'{self.data}' class _Dynamic(object): @@ -515,7 +510,7 @@ class _Dynamic(object): return not self.__eq__(other) def __repr__(self): - return '{}, {}'.format(self.pools, self.rules) + return f'{self.pools}, {self.rules}' class _DynamicMixin(object): @@ -546,12 +541,12 @@ class _DynamicMixin(object): else: for _id, pool in sorted(pools.items()): if not isinstance(pool, dict): - reasons.append('pool "{}" must be a dict'.format(_id)) + reasons.append(f'pool "{_id}" must be a dict') continue try: values = pool['values'] except KeyError: - reasons.append('pool "{}" is missing values'.format(_id)) + reasons.append(f'pool "{_id}" is missing values') continue pools_exist.add(_id) @@ -562,35 +557,33 @@ class _DynamicMixin(object): weight = value['weight'] weight = int(weight) if weight < 1 or weight > 15: - reasons.append('invalid weight "{}" in pool "{}" ' - 'value {}'.format(weight, _id, - value_num)) + reasons.append(f'invalid weight "{weight}" in ' + f'pool "{_id}" value {value_num}') except KeyError: pass except ValueError: - reasons.append('invalid weight "{}" in pool "{}" ' - 'value {}'.format(weight, _id, - value_num)) + reasons.append(f'invalid weight "{weight}" in ' + f'pool "{_id}" value {value_num}') try: value = value['value'] reasons.extend(cls._value_type.validate(value, cls._type)) except KeyError: - reasons.append('missing value in pool "{}" ' - 'value {}'.format(_id, value_num)) + reasons.append(f'missing value in pool "{_id}" ' + f'value {value_num}') if len(values) == 1 and values[0].get('weight', 1) != 1: - reasons.append('pool "{}" has single value with ' - 'weight!=1'.format(_id)) + reasons.append(f'pool "{_id}" has single value with ' + 'weight!=1') fallback = pool.get('fallback', None) if fallback is not None: if fallback in pools: pools_seen_as_fallback.add(fallback) else: - reasons.append('undefined fallback "{}" for pool "{}"' - .format(fallback, _id)) + reasons.append(f'undefined fallback "{fallback}" ' + f'for pool "{_id}"') # Check for loops fallback = pools[_id].get('fallback', None) @@ -600,8 +593,7 @@ class _DynamicMixin(object): fallback = pools.get(fallback, {}).get('fallback', None) if fallback in seen: loop = ' -> '.join(seen) - reasons.append('loop in pool fallbacks: {}' - .format(loop)) + reasons.append(f'loop in pool fallbacks: {loop}') # exit the loop break seen.append(fallback) @@ -623,7 +615,7 @@ class _DynamicMixin(object): try: pool = rule['pool'] except KeyError: - reasons.append('rule {} missing pool'.format(rule_num)) + reasons.append(f'rule {rule_num} missing pool') continue try: @@ -632,35 +624,32 @@ class _DynamicMixin(object): geos = [] if not isinstance(pool, string_types): - reasons.append('rule {} invalid pool "{}"' - .format(rule_num, pool)) + reasons.append(f'rule {rule_num} invalid pool "{pool}"') else: if pool not in pools: - reasons.append('rule {} undefined pool "{}"' - .format(rule_num, pool)) + reasons.append(f'rule {rule_num} undefined pool ' + f'"{pool}"') elif pool in pools_seen and geos: - reasons.append('rule {} invalid, target pool "{}" ' - 'reused'.format(rule_num, pool)) + reasons.append(f'rule {rule_num} invalid, target ' + f'pool "{pool}" reused') pools_seen.add(pool) if not geos: if seen_default: - reasons.append('rule {} duplicate default' - .format(rule_num)) + reasons.append(f'rule {rule_num} duplicate default') seen_default = True if not isinstance(geos, (list, tuple)): - reasons.append('rule {} geos must be a list' - .format(rule_num)) + reasons.append(f'rule {rule_num} geos must be a list') else: for geo in geos: - reasons.extend(GeoCodes.validate(geo, 'rule {} ' - .format(rule_num))) + reasons.extend(GeoCodes.validate(geo, + f'rule {rule_num} ')) unused = pools_exist - pools_seen - pools_seen_as_fallback if unused: unused = '", "'.join(sorted(unused)) - reasons.append('unused pools: "{}"'.format(unused)) + reasons.append(f'unused pools: "{unused}"') return reasons @@ -718,10 +707,9 @@ class _DynamicMixin(object): except AttributeError: values = self.value - return '<{} {} {}, {}, {}, {}>'.format(self.__class__.__name__, - self._type, self.ttl, - self.fqdn, values, - self.dynamic) + klass = self.__class__.__name__ + return f'<{klass} {self._type} {self.ttl}, {self.fqdn}, ' \ + f'{values}, {self.dynamic}>' return super(_DynamicMixin, self).__repr__() @@ -743,8 +731,8 @@ class _IpList(object): try: cls._address_type(text_type(value)) except Exception: - reasons.append('invalid {} address "{}"' - .format(cls._address_name, value)) + addr_name = cls._address_name + reasons.append(f'invalid {addr_name} address "{value}"') return reasons @classmethod @@ -780,11 +768,9 @@ class _TargetValue(object): # NOTE: FQDN complains if the data it receives isn't a str, it doesn't # allow unicode... This is likely specific to 2.7 elif not FQDN(str(data), allow_underscores=True).is_valid: - reasons.append('{} value "{}" is not a valid FQDN' - .format(_type, data)) + reasons.append(f'{_type} value "{data}" is not a valid FQDN') elif not data.endswith('.'): - reasons.append('{} value "{}" missing trailing .' - .format(_type, data)) + reasons.append(f'{_type} value "{data}" missing trailing .') return reasons @classmethod @@ -841,9 +827,9 @@ class CaaValue(EqualityTupleMixin): try: flags = int(value.get('flags', 0)) if flags < 0 or flags > 255: - reasons.append('invalid flags "{}"'.format(flags)) + reasons.append(f'invalid flags "{flags}"') except ValueError: - reasons.append('invalid flags "{}"'.format(value['flags'])) + reasons.append(f'invalid flags "{value["flags"]}"') if 'tag' not in value: reasons.append('missing tag') @@ -872,7 +858,7 @@ class CaaValue(EqualityTupleMixin): return (self.flags, self.tag, self.value) def __repr__(self): - return '{} {} "{}"'.format(self.flags, self.tag, self.value) + return f'{self.flags} {self.tag} "{self.value}"' class CaaRecord(_ValuesMixin, Record): @@ -943,13 +929,12 @@ class LocValue(EqualityTupleMixin): not 0 <= int(value[key]) <= 59 ) ): - reasons.append('invalid value for {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid value for {key} ' + f'"{value[key]}"') except KeyError: - reasons.append('missing {}'.format(key)) + reasons.append(f'missing {key}') except ValueError: - reasons.append('invalid {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid {key} "{value[key]}"') for key in float_keys: try: @@ -968,13 +953,12 @@ class LocValue(EqualityTupleMixin): not 0 <= float(value[key]) <= 90000000.00 ) ): - reasons.append('invalid value for {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid value for {key} ' + f'"{value[key]}"') except KeyError: - reasons.append('missing {}'.format(key)) + reasons.append(f'missing {key}') except ValueError: - reasons.append('invalid {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid {key} "{value[key]}"') for key in direction_keys: try: @@ -983,16 +967,16 @@ class LocValue(EqualityTupleMixin): key == 'lat_direction' and value[key] not in ['N', 'S'] ): - reasons.append('invalid direction for {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid direction for {key} ' + f'"{value[key]}"') if ( key == 'long_direction' and value[key] not in ['E', 'W'] ): - reasons.append('invalid direction for {} "{}"' - .format(key, value[key])) + reasons.append(f'invalid direction for {key} ' + f'"{value[key]}"') except KeyError: - reasons.append('missing {}'.format(key)) + reasons.append(f'missing {key}') return reasons @classmethod @@ -1063,23 +1047,12 @@ class LocValue(EqualityTupleMixin): ) def __repr__(self): - loc_format = "'{0} {1} {2:.3f} {3} " + \ - "{4} {5} {6:.3f} {7} " + \ - "{8:.2f}m {9:.2f}m {10:.2f}m {11:.2f}m'" - return loc_format.format( - self.lat_degrees, - self.lat_minutes, - self.lat_seconds, - self.lat_direction, - self.long_degrees, - self.long_minutes, - self.long_seconds, - self.long_direction, - self.altitude, - self.size, - self.precision_horz, - self.precision_vert, - ) + return f"'{self.lat_degrees} {self.lat_minutes} " \ + f"{self.lat_seconds:.3f} {self.lat_direction} " \ + f"{self.long_degrees} {self.long_minutes} " \ + f"{self.long_seconds:.3f} {self.long_direction} " \ + f"{self.altitude:.2f}m {self.size:.2f}m " \ + f"{self.precision_horz:.2f}m {self.precision_vert:.2f}m'" class LocRecord(_ValuesMixin, Record): @@ -1103,14 +1076,12 @@ class MxValue(EqualityTupleMixin): except KeyError: reasons.append('missing preference') except ValueError: - reasons.append('invalid preference "{}"' - .format(value['preference'])) + reasons.append(f'invalid preference "{value["preference"]}"') exchange = None try: exchange = value.get('exchange', None) or value['value'] if not exchange.endswith('.'): - reasons.append('MX value "{}" missing trailing .' - .format(exchange)) + reasons.append(f'MX value "{exchange}" missing trailing .') except KeyError: reasons.append('missing exchange') return reasons @@ -1147,7 +1118,7 @@ class MxValue(EqualityTupleMixin): return (self.preference, self.exchange) def __repr__(self): - return "'{} {}'".format(self.preference, self.exchange) + return f"'{self.preference} {self.exchange}'" class MxRecord(_ValuesMixin, Record): @@ -1169,25 +1140,24 @@ class NaptrValue(EqualityTupleMixin): except KeyError: reasons.append('missing order') except ValueError: - reasons.append('invalid order "{}"'.format(value['order'])) + reasons.append(f'invalid order "{value["order"]}"') try: int(value['preference']) except KeyError: reasons.append('missing preference') except ValueError: - reasons.append('invalid preference "{}"' - .format(value['preference'])) + reasons.append(f'invalid preference "{value["preference"]}"') try: flags = value['flags'] if flags not in cls.VALID_FLAGS: - reasons.append('unrecognized flags "{}"'.format(flags)) + reasons.append(f'unrecognized flags "{flags}"') except KeyError: reasons.append('missing flags') # TODO: validate these... they're non-trivial for k in ('service', 'regexp', 'replacement'): if k not in value: - reasons.append('missing {}'.format(k)) + reasons.append(f'missing {k}') return reasons @@ -1225,9 +1195,8 @@ class NaptrValue(EqualityTupleMixin): flags = self.flags if self.flags is not None else '' service = self.service if self.service is not None else '' regexp = self.regexp if self.regexp is not None else '' - return "'{} {} \"{}\" \"{}\" \"{}\" {}'" \ - .format(self.order, self.preference, flags, service, regexp, - self.replacement) + return f"'{self.order} {self.preference} \"{flags}\" \"{service}\" " \ + f"\"{regexp}\" {self.replacement}'" class NaptrRecord(_ValuesMixin, Record): @@ -1246,8 +1215,7 @@ class _NsValue(object): reasons = [] for value in data: if not value.endswith('.'): - reasons.append('NS value "{}" missing trailing .' - .format(value)) + reasons.append(f'NS value "{value}" missing trailing .') return reasons @classmethod @@ -1306,23 +1274,21 @@ class SshfpValue(EqualityTupleMixin): try: algorithm = int(value['algorithm']) if algorithm not in cls.VALID_ALGORITHMS: - reasons.append('unrecognized algorithm "{}"' - .format(algorithm)) + reasons.append(f'unrecognized algorithm "{algorithm}"') except KeyError: reasons.append('missing algorithm') except ValueError: - reasons.append('invalid algorithm "{}"' - .format(value['algorithm'])) + reasons.append(f'invalid algorithm "{value["algorithm"]}"') try: fingerprint_type = int(value['fingerprint_type']) if fingerprint_type not in cls.VALID_FINGERPRINT_TYPES: - reasons.append('unrecognized fingerprint_type "{}"' - .format(fingerprint_type)) + reasons.append('unrecognized fingerprint_type ' + f'"{fingerprint_type}"') except KeyError: reasons.append('missing fingerprint_type') except ValueError: - reasons.append('invalid fingerprint_type "{}"' - .format(value['fingerprint_type'])) + reasons.append('invalid fingerprint_type ' + f'"{value["fingerprint_type"]}"') if 'fingerprint' not in value: reasons.append('missing fingerprint') return reasons @@ -1351,8 +1317,7 @@ class SshfpValue(EqualityTupleMixin): return (self.algorithm, self.fingerprint_type, self.fingerprint) def __repr__(self): - return "'{} {} {}'".format(self.algorithm, self.fingerprint_type, - self.fingerprint) + return f"'{self.algorithm} {self.fingerprint_type} {self.fingerprint}'" class SshfpRecord(_ValuesMixin, Record): @@ -1369,7 +1334,7 @@ class _ChunkedValuesMixin(_ValuesMixin): vs = [value[i:i + self.CHUNK_SIZE] for i in range(0, len(value), self.CHUNK_SIZE)] vs = '" "'.join(vs) - return '"{}"'.format(vs) + return f'"{vs}"' @property def chunked_values(self): @@ -1391,7 +1356,7 @@ class _ChunkedValue(object): reasons = [] for value in data: if cls._unescaped_semicolon_re.search(value): - reasons.append('unescaped ; in "{}"'.format(value)) + reasons.append(f'unescaped ; in "{value}"') return reasons @classmethod @@ -1423,24 +1388,23 @@ class SrvValue(EqualityTupleMixin): except KeyError: reasons.append('missing priority') except ValueError: - reasons.append('invalid priority "{}"' - .format(value['priority'])) + reasons.append(f'invalid priority "{value["priority"]}"') try: int(value['weight']) except KeyError: reasons.append('missing weight') except ValueError: - reasons.append('invalid weight "{}"'.format(value['weight'])) + reasons.append(f'invalid weight "{value["weight"]}"') try: int(value['port']) except KeyError: reasons.append('missing port') except ValueError: - reasons.append('invalid port "{}"'.format(value['port'])) + reasons.append(f'invalid port "{value["port"]}"') try: if not value['target'].endswith('.'): - reasons.append('SRV value "{}" missing trailing .' - .format(value['target'])) + reasons.append(f'SRV value "{value["target"]}" missing ' + 'trailing .') except KeyError: reasons.append('missing target') return reasons @@ -1471,8 +1435,7 @@ class SrvValue(EqualityTupleMixin): return (self.priority, self.weight, self.port, self.target) def __repr__(self): - return "'{} {} {} {}'".format(self.priority, self.weight, self.port, - self.target) + return f"'{self.priority} {self.weight} {self.port} {self.target}'" class SrvRecord(_ValuesMixin, Record): @@ -1512,36 +1475,30 @@ class UrlfwdValue(EqualityTupleMixin): try: code = int(value['code']) if code not in cls.VALID_CODES: - reasons.append('unrecognized return code "{}"' - .format(code)) + reasons.append(f'unrecognized return code "{code}"') except KeyError: reasons.append('missing code') except ValueError: - reasons.append('invalid return code "{}"' - .format(value['code'])) + reasons.append(f'invalid return code "{value["code"]}"') try: masking = int(value['masking']) if masking not in cls.VALID_MASKS: - reasons.append('unrecognized masking setting "{}"' - .format(masking)) + reasons.append(f'unrecognized masking setting "{masking}"') except KeyError: reasons.append('missing masking') except ValueError: - reasons.append('invalid masking setting "{}"' - .format(value['masking'])) + reasons.append(f'invalid masking setting "{value["masking"]}"') try: query = int(value['query']) if query not in cls.VALID_QUERY: - reasons.append('unrecognized query setting "{}"' - .format(query)) + reasons.append(f'unrecognized query setting "{query}"') except KeyError: reasons.append('missing query') except ValueError: - reasons.append('invalid query setting "{}"' - .format(value['query'])) + reasons.append(f'invalid query setting "{value["query"]}"') for k in ('path', 'target'): if k not in value: - reasons.append('missing {}'.format(k)) + reasons.append(f'missing {k}') return reasons @classmethod @@ -1572,8 +1529,8 @@ class UrlfwdValue(EqualityTupleMixin): return (self.path, self.target, self.code, self.masking, self.query) def __repr__(self): - return '"{}" "{}" {} {} {}'.format(self.path, self.target, self.code, - self.masking, self.query) + return f'"{self.path}" "{self.target}" {self.code} ' \ + f'{self.masking} {self.query}' class UrlfwdRecord(_ValuesMixin, Record): diff --git a/octodns/record/geo.py b/octodns/record/geo.py index 0a2f1a3..f2b8c0f 100644 --- a/octodns/record/geo.py +++ b/octodns/record/geo.py @@ -24,15 +24,14 @@ class GeoCodes(object): pieces = code.split('-') n = len(pieces) if n > 3: - reasons.append('{}invalid geo code "{}"'.format(prefix, code)) + reasons.append(f'{prefix}invalid geo code "{code}"') elif n > 0 and pieces[0] not in geo_data: - reasons.append('{}unknown continent code "{}"' - .format(prefix, code)) + reasons.append(f'{prefix}unknown continent code "{code}"') elif n > 1 and pieces[1] not in geo_data[pieces[0]]: - reasons.append('{}unknown country code "{}"'.format(prefix, code)) + reasons.append(f'{prefix}unknown country code "{code}"') elif n > 2 and \ pieces[2] not in geo_data[pieces[0]][pieces[1]]['provinces']: - reasons.append('{}unknown province code "{}"'.format(prefix, code)) + reasons.append(f'{prefix}unknown province code "{code}"') return reasons @@ -57,7 +56,7 @@ class GeoCodes(object): def country_to_code(cls, country): for continent, countries in geo_data.items(): if country in countries: - return '{}-{}'.format(continent, country) + return f'{continent}-{country}' cls.log.warn('country_to_code: unrecognized country "%s"', country) return @@ -74,4 +73,4 @@ class GeoCodes(object): country = 'US' if province in geo_data['NA']['CA']['provinces']: country = 'CA' - return 'NA-{}-{}'.format(country, province) + return f'NA-{country}-{province}' From b749d8cc32c15a598a5de0a88b6cb11aef5607a4 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 2 Sep 2021 16:49:52 -0700 Subject: [PATCH 02/34] f-strings for octodns/source/* --- octodns/source/axfr.py | 8 ++++---- octodns/source/envvar.py | 6 +++--- octodns/source/tinydns.py | 17 ++++++++--------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/octodns/source/axfr.py b/octodns/source/axfr.py index 7a45155..fb6b8d7 100644 --- a/octodns/source/axfr.py +++ b/octodns/source/axfr.py @@ -151,7 +151,7 @@ class AxfrBaseSource(BaseSource): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -181,7 +181,7 @@ class AxfrSource(AxfrBaseSource): master: ns1.example.com ''' def __init__(self, id, master): - self.log = logging.getLogger('AxfrSource[{}]'.format(id)) + self.log = logging.getLogger(f'AxfrSource[{id}]') self.log.debug('__init__: id=%s, master=%s', id, master) super(AxfrSource, self).__init__(id) self.master = master @@ -244,7 +244,7 @@ class ZoneFileSource(AxfrBaseSource): check_origin: false ''' def __init__(self, id, directory, file_extension='.', check_origin=True): - self.log = logging.getLogger('ZoneFileSource[{}]'.format(id)) + self.log = logging.getLogger(f'ZoneFileSource[{id}]') self.log.debug('__init__: id=%s, directory=%s, file_extension=%s, ' 'check_origin=%s', id, directory, file_extension, check_origin) @@ -256,7 +256,7 @@ class ZoneFileSource(AxfrBaseSource): self._zone_records = {} def _load_zone_file(self, zone_name): - zone_filename = '{}{}'.format(zone_name[:-1], self.file_extension) + zone_filename = f'{zone_name[:-1]}{self.file_extension}' zonefiles = listdir(self.directory) if zone_filename in zonefiles: try: diff --git a/octodns/source/envvar.py b/octodns/source/envvar.py index adf267a..9f54b3b 100644 --- a/octodns/source/envvar.py +++ b/octodns/source/envvar.py @@ -13,7 +13,7 @@ class EnvVarSourceException(Exception): class EnvironmentVariableNotFoundException(EnvVarSourceException): def __init__(self, data): super(EnvironmentVariableNotFoundException, self).__init__( - 'Unknown environment variable {}'.format(data)) + f'Unknown environment variable {data}') class EnvVarSource(BaseSource): @@ -63,8 +63,8 @@ class EnvVarSource(BaseSource): DEFAULT_TTL = 60 def __init__(self, id, variable, name, ttl=DEFAULT_TTL): - self.log = logging.getLogger('{}[{}]'.format( - self.__class__.__name__, id)) + klass = self.__class__.__name__ + self.log = logging.getLogger(f'{klass}[{id}]') self.log.debug('__init__: id=%s, variable=%s, name=%s, ' 'ttl=%d', id, variable, name, ttl) super(EnvVarSource, self).__init__(id) diff --git a/octodns/source/tinydns.py b/octodns/source/tinydns.py index 9c44ed8..2fdf3cc 100755 --- a/octodns/source/tinydns.py +++ b/octodns/source/tinydns.py @@ -90,7 +90,7 @@ class TinyDnsBaseSource(BaseSource): return { 'ttl': ttl, 'type': _type, - 'value': '{}.'.format(first[0]) + 'value': f'{first[0]}.' } def _data_for_MX(self, _type, records): @@ -103,7 +103,7 @@ class TinyDnsBaseSource(BaseSource): 'type': _type, 'values': [{ 'preference': r[1], - 'exchange': '{}.'.format(r[0]) + 'exchange': f'{r[0]}.' } for r in records] } @@ -115,7 +115,7 @@ class TinyDnsBaseSource(BaseSource): return { 'ttl': ttl, 'type': _type, - 'values': ['{}.'.format(r[0]) for r in records] + 'values': [f'{r[0]}.' for r in records] } def populate(self, zone, target=False, lenient=False): @@ -168,7 +168,7 @@ class TinyDnsBaseSource(BaseSource): for name, types in data.items(): for _type, d in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data = data_for(_type, d) if data: record = Record.new(zone, name, data, source=self, @@ -196,11 +196,11 @@ class TinyDnsBaseSource(BaseSource): if line[0].endswith('in-addr.arpa'): # since it's already in in-addr.arpa format match = name_re.match(line[0]) - value = '{}.'.format(line[1]) + value = f'{line[1]}.' else: addr = ip_address(line[1]) match = name_re.match(addr.reverse_pointer) - value = '{}.'.format(line[0]) + value = f'{line[0]}.' if match: try: @@ -217,8 +217,7 @@ class TinyDnsBaseSource(BaseSource): try: zone.add_record(record, lenient=lenient) except DuplicateRecordException: - self.log.warn('Duplicate PTR record for {}, ' - 'skipping'.format(addr)) + self.log.warn(f'Duplicate PTR record for {addr}, skipping') class TinyDnsFileSource(TinyDnsBaseSource): @@ -236,7 +235,7 @@ class TinyDnsFileSource(TinyDnsBaseSource): NOTE: timestamps & lo fields are ignored if present. ''' def __init__(self, id, directory, default_ttl=3600): - self.log = logging.getLogger('TinyDnsFileSource[{}]'.format(id)) + self.log = logging.getLogger(f'TinyDnsFileSource[{id}]') self.log.debug('__init__: id=%s, directory=%s, default_ttl=%d', id, directory, default_ttl) super(TinyDnsFileSource, self).__init__(id, default_ttl) From bd8e9c9c14ddb4099d921cf26d064505e684e579 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Fri, 3 Sep 2021 09:54:43 -0700 Subject: [PATCH 03/34] f-string some regexes in sources --- octodns/source/tinydns.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/octodns/source/tinydns.py b/octodns/source/tinydns.py index 2fdf3cc..4615ebe 100755 --- a/octodns/source/tinydns.py +++ b/octodns/source/tinydns.py @@ -144,7 +144,7 @@ class TinyDnsBaseSource(BaseSource): '3': 'AAAA', '6': 'AAAA', } - name_re = re.compile(r'((?P.+)\.)?{}$'.format(zone.name[:-1])) + name_re = re.compile(fr'((?P.+)\.)?{zone.name[:-1]}$') data = defaultdict(lambda: defaultdict(list)) for line in self._lines(): @@ -180,7 +180,7 @@ class TinyDnsBaseSource(BaseSource): 'record=%s', record) def _populate_in_addr_arpa(self, zone, lenient): - name_re = re.compile(r'(?P.+)\.{}$'.format(zone.name[:-1])) + name_re = re.compile(fr'(?P.+)\.{zone.name[:-1]}$') for line in self._lines(): _type = line[0] From 67e79481bd081829888d1813675ebfa60d8c3a34 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Fri, 3 Sep 2021 09:58:08 -0700 Subject: [PATCH 04/34] f-strings for cmds and processors --- octodns/cmds/args.py | 2 +- octodns/cmds/report.py | 5 +++-- octodns/processor/ownership.py | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/octodns/cmds/args.py b/octodns/cmds/args.py index 4867ae3..41906ba 100644 --- a/octodns/cmds/args.py +++ b/octodns/cmds/args.py @@ -25,7 +25,7 @@ class ArgumentParser(_Base): super(ArgumentParser, self).__init__(*args, **kwargs) def parse_args(self, default_log_level=INFO): - version = 'octoDNS {}'.format(__VERSION__) + version = f'octoDNS {__VERSION__}' self.add_argument('--version', action='version', version=version, help='Print octoDNS version and exit') self.add_argument('--log-stream-stdout', action='store_true', diff --git a/octodns/cmds/report.py b/octodns/cmds/report.py index d0b82c0..381381b 100755 --- a/octodns/cmds/report.py +++ b/octodns/cmds/report.py @@ -53,13 +53,14 @@ def main(): try: sources = [manager.providers[source] for source in args.source] except KeyError as e: - raise Exception('Unknown source: {}'.format(e.args[0])) + raise Exception(f'Unknown source: {e.args[0]}') zone = manager.get_zone(args.zone) for source in sources: source.populate(zone) - print('name,type,ttl,{},consistent'.format(','.join(args.server))) + servers = ','.join(args.server) + print(f'name,type,ttl,{servers},consistent') resolvers = [] ip_addr_re = re.compile(r'^[\d\.]+$') for server in args.server: diff --git a/octodns/processor/ownership.py b/octodns/processor/ownership.py index 42f041d..a70c8dd 100644 --- a/octodns/processor/ownership.py +++ b/octodns/processor/ownership.py @@ -29,10 +29,9 @@ class OwnershipProcessor(BaseProcessor): # Then create and add an ownership TXT for each of them record_name = record.name.replace('*', '_wildcard') if record.name: - name = '{}.{}.{}'.format(self.txt_name, record._type, - record_name) + name = f'{self.txt_name}.{record._type}.{record_name}' else: - name = '{}.{}'.format(self.txt_name, record._type) + name = f'{self.txt_name}.{record._type}' txt = Record.new(desired, name, { 'type': 'TXT', 'ttl': 60, From d49af6ee31ae34863eddd06f18c97a82c10e6a48 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:15:09 -0700 Subject: [PATCH 05/34] f-strings for AzureProvider --- octodns/provider/azuredns.py | 81 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index 0b4e1c9..cdb6e90 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -116,12 +116,12 @@ class _AzureRecord(object): return # Refer to function docstring for key_name and class_name. - key_name = '{}_records'.format(self.record_type).lower() + key_name = f'{self.record_type}_records'.lower() if record._type == 'CNAME': key_name = key_name[:-1] azure_class = self.TYPE_MAP[self.record_type] - params_for = getattr(self, '_params_for_{}'.format(record._type)) + params_for = getattr(self, f'_params_for_{record._type}') self.params = params_for(record.data, key_name, azure_class) self.params['ttl'] = record.ttl @@ -228,7 +228,7 @@ class _AzureRecord(object): ''' def key_dict(d): - return sum([hash('{}:{}'.format(k, v)) for k, v in d.items()]) + return sum([hash(f'{k}:{v}') for k, v in d.items()]) def parse_dict(params): vals = [] @@ -272,18 +272,18 @@ def _root_traffic_manager_name(record): # hoping that real life FQDNs won't have double hyphens name = record.fqdn[:-1].replace('.', '--') if record._type != 'CNAME': - name += '-{}'.format(record._type) + name += f'-{record._type}' return name def _rule_traffic_manager_name(pool, record): prefix = _root_traffic_manager_name(record) - return '{}-rule-{}'.format(prefix, pool) + return f'{prefix}-rule-{pool}' def _pool_traffic_manager_name(pool, record): prefix = _root_traffic_manager_name(record) - return '{}-pool-{}'.format(prefix, pool) + return f'{prefix}-pool-{pool}' def _get_monitor(record): @@ -314,14 +314,14 @@ def _check_valid_dynamic(record): if defaults != vals: # we don't yet support multi-value defaults, specifying all # pool values allows for Traffic Manager profile optimization - msg = ('{} {}: Values of A/AAAA dynamic records must either ' - 'have a single value or contain all values from all ' - 'pools') - raise AzureException(msg.format(record.fqdn, record._type)) + raise AzureException(f'{record.fqdn} {record._type}: Values ' + 'of A/AAAA dynamic records must either ' + 'have a single value or contain all ' + 'values from all pools') elif typ != 'CNAME': # dynamic records of unsupported type - msg = '{}: Dynamic records in Azure must be of type A/AAAA/CNAME' - raise AzureException(msg.format(record.fqdn)) + raise AzureException(f'{record.fqdn}: Dynamic records in Azure must ' + 'be of type A/AAAA/CNAME') def _profile_is_match(have, desired): @@ -331,7 +331,7 @@ def _profile_is_match(have, desired): log = logging.getLogger('azuredns._profile_is_match').debug def false(have, desired, name=None): - prefix = 'profile={}'.format(name) if name else '' + prefix = f'profile={name}' if name else '' attr = have.__class__.__name__ log('%s have.%s = %s', prefix, attr, have) log('%s desired.%s = %s', prefix, attr, desired) @@ -463,7 +463,7 @@ class AzureProvider(BaseProvider): def __init__(self, id, client_id, key, directory_id, sub_id, resource_group, *args, **kwargs): - self.log = logging.getLogger('AzureProvider[{}]'.format(id)) + self.log = logging.getLogger(f'AzureProvider[{id}]') self.log.debug('__init__: id=%s, client_id=%s, ' 'key=***, directory_id:%s', id, client_id, directory_id) super(AzureProvider, self).__init__(id, *args, **kwargs) @@ -635,7 +635,7 @@ class AzureProvider(BaseProvider): record_name = azrecord.name if azrecord.name != '@' else '' typ = _parse_azure_type(azrecord.type) - data_for = getattr(self, '_data_for_{}'.format(typ)) + data_for = getattr(self, f'_data_for_{typ}') data = data_for(azrecord) data['type'] = typ data['ttl'] = azrecord.ttl @@ -755,13 +755,13 @@ class AzureProvider(BaseProvider): # Throw exception otherwise, it should not happen if the # profile was generated by octoDNS if 'GEO-AS' not in geo_map: - msg = 'Profile={} for record {}: '.format( - root_profile.name, azrecord.fqdn) - msg += 'Middle East (GEO-ME) is not supported by ' + \ - 'octoDNS. It needs to be either paired ' + \ - 'with Asia (GEO-AS) or expanded into ' + \ - 'individual list of countries.' - raise AzureException(msg) + raise AzureException(f'Profile={root_profile.name} ' + f'for record {azrecord.fqdn}: ' + 'Middle East (GEO-ME) is not ' + 'supported by octoDNS. It needs ' + 'to be either paired with Asia ' + '(GEO-AS) or expanded into ' + 'individual list of countries.') geo_map.remove('GEO-ME') geos = rule.setdefault('geos', []) for code in geo_map: @@ -779,7 +779,7 @@ class AzureProvider(BaseProvider): # state country, province = code.split('-', 1) country = GeoCodes.country_to_code(country) - geos.append('{}-{}'.format(country, province)) + geos.append(f'{country}-{province}') elif code == 'WORLD': geos.append(code) else: @@ -904,17 +904,17 @@ class AzureProvider(BaseProvider): if not ep.target: continue if ep.target in endpoints: - msg = '{} contains duplicate endpoint {}' - raise AzureException(msg.format(name, ep.target)) + raise AzureException(f'{name} contains duplicate ' + f'endpoint {ep.target}') endpoints.add(ep.target) if name in seen_profiles: # exit if a possible collision is detected, even though # we've tried to ensure unique mapping - msg = 'Collision in Traffic Manager names detected' - msg = '{}: {} and {} both want to use {}'.format( - msg, seen_profiles[name], record.fqdn, name) - raise AzureException(msg) + raise AzureException('Collision in Traffic Manager names ' + f'detected: {seen_profiles[name]} ' + f'and {record.fqdn} both want to ' + f'use {name}') else: seen_profiles[name] = record.fqdn @@ -952,10 +952,9 @@ class AzureProvider(BaseProvider): elif ep.target: ep.type = endpoint_type_prefix + 'externalEndpoints' else: - msg = ('Invalid endpoint {} in profile {}, needs to have ' + - 'either target or target_resource_id').format( - ep.name, name) - raise AzureException(msg) + raise AzureException(f'Invalid endpoint {ep.name} in profile ' + f'{name}, needs to have either target ' + 'or target_resource_id') # build and return return Profile( @@ -1028,7 +1027,7 @@ class AzureProvider(BaseProvider): # Oceania geo = 'AP' - geos.append('GEO-{}'.format(geo)) + geos.append(f'GEO-{geo}') if not geos or pool_name == world_pool: geos.append('WORLD') world_seen = True @@ -1050,7 +1049,7 @@ class AzureProvider(BaseProvider): # strip trailing dot from CNAME value if typ == 'CNAME': target = target[:-1] - ep_name = '{}--{}'.format(pool_name, target) + ep_name = f'{pool_name}--{target}' # Endpoint names cannot have colons, drop them # from IPv6 addresses ep_name = ep_name.replace(':', '-') @@ -1180,8 +1179,8 @@ class AzureProvider(BaseProvider): # match existing profiles with record's prefix name = profile_id.split('/')[-1] if name == tm_prefix or \ - name.startswith('{}-pool-'.format(tm_prefix)) or \ - name.startswith('{}-rule-'.format(tm_prefix)): + name.startswith(f'{tm_prefix}-pool-') or \ + name.startswith(f'{tm_prefix}-rule-'): profiles.add(name) return profiles @@ -1236,7 +1235,7 @@ class AzureProvider(BaseProvider): root_profile.endpoints = endpoints self._sync_traffic_managers([root_profile]) - self.log.debug('* Success Create: {}'.format(record)) + self.log.debug('* Success Create: %s', record) def _apply_Update(self, change): '''A record from change must be created. @@ -1300,7 +1299,7 @@ class AzureProvider(BaseProvider): # changed to a simple record self._traffic_managers_gc(existing, set()) - self.log.debug('* Success Update: {}'.format(new)) + self.log.debug('* Success Update: %s', new) def _apply_Delete(self, change): '''A record from change must be deleted. @@ -1320,7 +1319,7 @@ class AzureProvider(BaseProvider): if getattr(record, 'dynamic', False): self._traffic_managers_gc(record, set()) - self.log.debug('* Success Delete: {}'.format(record)) + self.log.debug('* Success Delete: %s', record) def _apply(self, plan): '''Required function of manager.py to actually apply a record change. @@ -1353,4 +1352,4 @@ class AzureProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ if class_name != 'Delete': - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) From de3b4a58361c536dc6a5d42c4ae1351cd05db3a6 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:18:57 -0700 Subject: [PATCH 06/34] f-strings for BaseProvider --- octodns/provider/base.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/octodns/provider/base.py b/octodns/provider/base.py index b636d65..9f334f0 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -57,10 +57,9 @@ class BaseProvider(BaseSource): for record in desired.records: if record._type == 'PTR' and len(record.values) > 1: # replace with a single-value copy - msg = 'multi-value PTR records not supported for {}' \ - .format(record.fqdn) - fallback = 'falling back to single value, {}' \ - .format(record.value) + msg = \ + f'multi-value PTR records not supported for {record.fqdn}' + fallback = f'falling back to single value, {record.value}' self.supports_warn_or_except(msg, fallback) record = record.copy() record.values = [record.value] @@ -85,8 +84,8 @@ class BaseProvider(BaseSource): def supports_warn_or_except(self, msg, fallback): if self.strict_supports: - raise SupportsException('{}: {}'.format(self.id, msg)) - self.log.warning('{}; {}'.format(msg, fallback)) + raise SupportsException(f'{self.id}: {msg}') + self.log.warning('%s; %s', msg, fallback) def plan(self, desired, processors=[]): self.log.info('plan: desired=%s', desired.name) From f9280d327407b30d44b1b8f3d59ff77be4e17bf0 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:22:38 -0700 Subject: [PATCH 07/34] f-strings for CloudflareProvider --- octodns/provider/cloudflare.py | 107 ++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/octodns/provider/cloudflare.py b/octodns/provider/cloudflare.py index a774acc..517a364 100644 --- a/octodns/provider/cloudflare.py +++ b/octodns/provider/cloudflare.py @@ -86,7 +86,7 @@ class CloudflareProvider(BaseProvider): def __init__(self, id, email=None, token=None, cdn=False, retry_count=4, retry_period=300, zones_per_page=50, records_per_page=100, *args, **kwargs): - self.log = getLogger('CloudflareProvider[{}]'.format(id)) + self.log = getLogger(f'CloudflareProvider[{id}]') self.log.debug('__init__: id=%s, email=%s, token=***, cdn=%s', id, email, cdn) super(CloudflareProvider, self).__init__(id, *args, **kwargs) @@ -101,7 +101,7 @@ class CloudflareProvider(BaseProvider): # https://api.cloudflare.com/#getting-started-requests # https://tools.ietf.org/html/rfc6750#section-2.1 sess.headers.update({ - 'Authorization': 'Bearer {}'.format(token), + 'Authorization': f'Bearer {token}', }) self.cdn = cdn self.retry_count = retry_count @@ -130,7 +130,7 @@ class CloudflareProvider(BaseProvider): def _request(self, method, path, params=None, data=None): self.log.debug('_request: method=%s, path=%s', method, path) - url = 'https://api.cloudflare.com/client/v4{}'.format(path) + url = f'https://api.cloudflare.com/client/v4{path}' resp = self._sess.request(method, url, params=params, json=data, timeout=self.TIMEOUT) self.log.debug('_request: status=%d', resp.status_code) @@ -168,7 +168,7 @@ class CloudflareProvider(BaseProvider): else: page = None - self._zones = {'{}.'.format(z['name']): z['id'] for z in zones} + self._zones = {f'{z["name"]}.': z['id'] for z in zones} return self._zones @@ -184,7 +184,7 @@ class CloudflareProvider(BaseProvider): return { 'ttl': self._ttl_data(records[0]['ttl']), 'type': _type, - 'value': '{}.cdn.cloudflare.net.'.format(records[0]['name']), + 'value': f'{records[0]["name"]}.cdn.cloudflare.net.', } def _data_for_multiple(self, _type, records): @@ -221,7 +221,7 @@ class CloudflareProvider(BaseProvider): return { 'ttl': self._ttl_data(only['ttl']), 'type': _type, - 'value': '{}.'.format(only['content']) + 'value': f'{only["content"]}.' } _data_for_ALIAS = _data_for_CNAME @@ -256,7 +256,7 @@ class CloudflareProvider(BaseProvider): for r in records: values.append({ 'preference': r['priority'], - 'exchange': '{}.'.format(r['content']), + 'exchange': f'{r["content"]}.', }) return { 'ttl': self._ttl_data(records[0]['ttl']), @@ -268,13 +268,13 @@ class CloudflareProvider(BaseProvider): return { 'ttl': self._ttl_data(records[0]['ttl']), 'type': _type, - 'values': ['{}.'.format(r['content']) for r in records], + 'values': [f'{r["content"]}.' for r in records], } def _data_for_SRV(self, _type, records): values = [] for r in records: - target = ('{}.'.format(r['data']['target']) + target = (f'{r["data"]["target"]}.' if r['data']['target'] != "." else ".") values.append({ 'priority': r['data']['priority'], @@ -311,7 +311,7 @@ class CloudflareProvider(BaseProvider): return [] records = [] - path = '/zones/{}/dns_records'.format(zone_id) + path = f'/zones/{zone_id}/dns_records' page = 1 while page: resp = self._try_request('GET', path, params={'page': page, @@ -323,7 +323,7 @@ class CloudflareProvider(BaseProvider): else: page = None - path = '/zones/{}/pagerules'.format(zone_id) + path = f'/zones/{zone_id}/pagerules' resp = self._try_request('GET', path, params={'status': 'active'}) for r in resp['result']: # assumption, base on API guide, will only contain 1 action @@ -343,7 +343,7 @@ class CloudflareProvider(BaseProvider): if _type == 'CNAME' and name == '': _type = 'ALIAS' - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data = data_for(_type, records) record = Record.new(zone, name, data, source=self, lenient=lenient) @@ -563,11 +563,11 @@ class CloudflareProvider(BaseProvider): _type = 'CNAME' if _type == 'URLFWD': - contents_for = getattr(self, '_contents_for_{}'.format(_type)) + contents_for = getattr(self, f'_contents_for_{_type}') for content in contents_for(record): yield content else: - contents_for = getattr(self, '_contents_for_{}'.format(_type)) + contents_for = getattr(self, f'_contents_for_{_type}') for content in contents_for(record): content.update({ 'name': name, @@ -597,46 +597,58 @@ class CloudflareProvider(BaseProvider): # AND... for URLFWD/Redirects additional adventures are created. _type = data.get('type', 'URLFWD') if _type == 'MX': - return '{priority} {content}'.format(**data) + priority = data['priority'] + content = data['content'] + return f'{priority} {content}' elif _type == 'CAA': data = data['data'] - return '{flags} {tag} {value}'.format(**data) + flags = data['flags'] + tag = data['tag'] + value = data['value'] + return f'{flags} {tag} {value}' elif _type == 'SRV': data = data['data'] - return '{port} {priority} {target} {weight}'.format(**data) + port = data['port'] + priority = data['priority'] + target = data['target'] + weight = data['weight'] + return f'{port} {priority} {target} {weight}' elif _type == 'LOC': data = data['data'] - loc = ( - '{lat_degrees}', - '{lat_minutes}', - '{lat_seconds}', - '{lat_direction}', - '{long_degrees}', - '{long_minutes}', - '{long_seconds}', - '{long_direction}', - '{altitude}', - '{size}', - '{precision_horz}', - '{precision_vert}') - return ' '.join(loc).format(**data) + lat_degrees = data['lat_degrees'] + lat_minutes = data['lat_minutes'] + lat_seconds = data['lat_seconds'] + lat_direction = data['lat_direction'] + long_degrees = data['long_degrees'] + long_minutes = data['long_minutes'] + long_seconds = data['long_seconds'] + long_direction = data['long_direction'] + altitude = data['altitude'] + size = data['size'] + precision_horz = data['precision_horz'] + precision_vert = data['precision_vert'] + return f'{lat_degrees} {lat_minutes} {lat_seconds} ' \ + f'{lat_direction} {long_degrees} {long_minutes} ' \ + f'{long_seconds} {long_direction} {altitude} {size} ' \ + f'{precision_horz} {precision_vert}' elif _type == 'URLFWD': uri = data['targets'][0]['constraint']['value'] uri = '//' + uri if not uri.startswith('http') else uri parsed_uri = urlsplit(uri) - return '{name} {path} {url} {status_code}' \ - .format(name=parsed_uri.netloc, - path=parsed_uri.path, - **data['actions'][0]['value']) + url = data['actions'][0]['value']['url'] + status_code = data['actions'][0]['value']['status_code'] + return f'{parsed_uri.netloc} {parsed_uri.path} {url} ' + \ + f'{status_code}' + return data['content'] def _apply_Create(self, change): new = change.new zone_id = self.zones[new.zone.name] if new._type == 'URLFWD': - path = '/zones/{}/pagerules'.format(zone_id) + path = f'/zones/{zone_id}/pagerules' else: - path = '/zones/{}/dns_records'.format(zone_id) + path = f'/zones/{zone_id}/dns_records' for content in self._gen_data(new): self._try_request('POST', path, data=content) @@ -738,9 +750,9 @@ class CloudflareProvider(BaseProvider): # Creates if _type == 'URLFWD': - path = '/zones/{}/pagerules'.format(zone_id) + path = f'/zones/{zone_id}/pagerules' else: - path = '/zones/{}/dns_records'.format(zone_id) + path = f'/zones/{zone_id}/dns_records' for _, data in sorted(creates.items()): self.log.debug('_apply_Update: creating %s', data) self._try_request('POST', path, data=data) @@ -751,9 +763,9 @@ class CloudflareProvider(BaseProvider): data = info['data'] old_data = info['old_data'] if _type == 'URLFWD': - path = '/zones/{}/pagerules/{}'.format(zone_id, record_id) + path = f'/zones/{zone_id}/pagerules/{record_id}' else: - path = '/zones/{}/dns_records/{}'.format(zone_id, record_id) + path = f'/zones/{zone_id}/dns_records/{record_id}' self.log.debug('_apply_Update: updating %s, %s -> %s', record_id, data, old_data) self._try_request('PUT', path, data=data) @@ -763,9 +775,9 @@ class CloudflareProvider(BaseProvider): record_id = info['record_id'] old_data = info['data'] if _type == 'URLFWD': - path = '/zones/{}/pagerules/{}'.format(zone_id, record_id) + path = f'/zones/{zone_id}/pagerules/{record_id}' else: - path = '/zones/{}/dns_records/{}'.format(zone_id, record_id) + path = f'/zones/{zone_id}/dns_records/{record_id}' self.log.debug('_apply_Update: removing %s, %s', record_id, old_data) self._try_request('DELETE', path) @@ -786,14 +798,13 @@ class CloudflareProvider(BaseProvider): zone_id = self.zones.get(existing.zone.name, False) if existing_name == record_name and \ existing_type == record_type: - path = '/zones/{}/pagerules/{}' \ - .format(zone_id, record['id']) + path = f'/zones/{zone_id}/pagerules/{record["id"]}' self._try_request('DELETE', path) else: if existing_name == record['name'] and \ existing_type == record['type']: - path = '/zones/{}/dns_records/{}' \ - .format(record['zone_id'], record['id']) + path = f'/zones/{record["zone_id"]}/dns_records/' \ + f'{record["id"]}' self._try_request('DELETE', path) def _apply(self, plan): @@ -821,7 +832,7 @@ class CloudflareProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # clear the cache self._zone_records.pop(name, None) From 5104467067cf5c91ad629bbc8db9046dcdc05275 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:32:06 -0700 Subject: [PATCH 08/34] f-strings for DigitalOceanProvider --- octodns/provider/digitalocean.py | 34 ++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/octodns/provider/digitalocean.py b/octodns/provider/digitalocean.py index fe31754..d368b46 100644 --- a/octodns/provider/digitalocean.py +++ b/octodns/provider/digitalocean.py @@ -35,11 +35,11 @@ class DigitalOceanClient(object): def __init__(self, token): sess = Session() - sess.headers.update({'Authorization': 'Bearer {}'.format(token)}) + sess.headers.update({'Authorization': f'Bearer {token}'}) self._sess = sess def _request(self, method, path, params=None, data=None): - url = '{}{}'.format(self.BASE, path) + url = f'{self.BASE}{path}' resp = self._sess.request(method, url, params=params, json=data) if resp.status_code == 401: raise DigitalOceanClientUnauthorized() @@ -49,7 +49,7 @@ class DigitalOceanClient(object): return resp def domain(self, name): - path = '/domains/{}'.format(name) + path = f'/domains/{name}' return self._request('GET', path).json() def domain_create(self, name): @@ -64,7 +64,7 @@ class DigitalOceanClient(object): self.record_delete(name, record['id']) def records(self, zone_name): - path = '/domains/{}/records'.format(zone_name) + path = f'/domains/{zone_name}/records' ret = [] page = 1 @@ -95,7 +95,7 @@ class DigitalOceanClient(object): return ret def record_create(self, zone_name, params): - path = '/domains/{}/records'.format(zone_name) + path = f'/domains/{zone_name}/records' # change empty name string to @, DO uses @ for apex record names if params['name'] == '': params['name'] = '@' @@ -103,7 +103,7 @@ class DigitalOceanClient(object): self._request('POST', path, data=params) def record_delete(self, zone_name, record_id): - path = '/domains/{}/records/{}'.format(zone_name, record_id) + path = f'/domains/{zone_name}/records/{record_id}' self._request('DELETE', path) @@ -121,7 +121,7 @@ class DigitalOceanProvider(BaseProvider): SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'TXT', 'SRV')) def __init__(self, id, token, *args, **kwargs): - self.log = logging.getLogger('DigitalOceanProvider[{}]'.format(id)) + self.log = logging.getLogger(f'DigitalOceanProvider[{id}]') self.log.debug('__init__: id=%s, token=***', id) super(DigitalOceanProvider, self).__init__(id, *args, **kwargs) self._client = DigitalOceanClient(token) @@ -157,7 +157,7 @@ class DigitalOceanProvider(BaseProvider): return { 'ttl': record['ttl'], 'type': _type, - 'value': '{}.'.format(record['data']) + 'value': f'{record["data"]}.' } def _data_for_MX(self, _type, records): @@ -165,7 +165,7 @@ class DigitalOceanProvider(BaseProvider): for record in records: values.append({ 'preference': record['priority'], - 'exchange': '{}.'.format(record['data']) + 'exchange': f'{record["data"]}.' }) return { 'ttl': records[0]['ttl'], @@ -176,8 +176,7 @@ class DigitalOceanProvider(BaseProvider): def _data_for_NS(self, _type, records): values = [] for record in records: - data = '{}.'.format(record['data']) - values.append(data) + values.append(f'{record["data"]}.') return { 'ttl': records[0]['ttl'], 'type': _type, @@ -187,10 +186,7 @@ class DigitalOceanProvider(BaseProvider): def _data_for_SRV(self, _type, records): values = [] for record in records: - target = ( - '{}.'.format(record['data']) - if record['data'] != "." else "." - ) + target = f'{record["data"]}.' if record['data'] != "." else "." values.append({ 'port': record['port'], 'priority': record['priority'], @@ -237,7 +233,7 @@ class DigitalOceanProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -263,7 +259,7 @@ class DigitalOceanProvider(BaseProvider): def _params_for_CAA(self, record): for value in record.values: yield { - 'data': '{}.'.format(value.value), + 'data': f'{value.value}.', 'flags': value.flags, 'name': record.name, 'tag': value.tag, @@ -316,7 +312,7 @@ class DigitalOceanProvider(BaseProvider): def _apply_Create(self, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self._client.record_create(new.zone.name[:-1], params) @@ -347,7 +343,7 @@ class DigitalOceanProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From 15b8cfde01c86b49eb2cda2376b0e9f1f2f4a775 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:33:27 -0700 Subject: [PATCH 09/34] f-strings for DnsimpleProvider --- octodns/provider/dnsimple.py | 44 ++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/octodns/provider/dnsimple.py b/octodns/provider/dnsimple.py index 009e829..1ce1673 100644 --- a/octodns/provider/dnsimple.py +++ b/octodns/provider/dnsimple.py @@ -35,7 +35,7 @@ class DnsimpleClient(object): def __init__(self, token, account, sandbox): self.account = account sess = Session() - sess.headers.update({'Authorization': 'Bearer {}'.format(token)}) + sess.headers.update({'Authorization': f'Bearer {token}'}) self._sess = sess if sandbox: self.base = 'https://api.sandbox.dnsimple.com/v2/' @@ -43,7 +43,7 @@ class DnsimpleClient(object): self.base = 'https://api.dnsimple.com/v2/' def _request(self, method, path, params=None, data=None): - url = '{}{}{}'.format(self.base, self.account, path) + url = f'{self.base}{self.account}{path}' resp = self._sess.request(method, url, params=params, json=data) if resp.status_code == 401: raise DnsimpleClientUnauthorized() @@ -53,7 +53,7 @@ class DnsimpleClient(object): return resp def zone(self, name): - path = '/zones/{}'.format(name) + path = f'/zones/{name}' return self._request('GET', path).json() def domain_create(self, name): @@ -64,7 +64,7 @@ class DnsimpleClient(object): page = 1 while True: - data = self._request('GET', '/zones/{}/records'.format(zone_name), + data = self._request('GET', f'/zones/{zone_name}/records', {'page': page}).json() ret += data['data'] pagination = data['pagination'] @@ -75,11 +75,11 @@ class DnsimpleClient(object): return ret def record_create(self, zone_name, params): - path = '/zones/{}/records'.format(zone_name) + path = f'/zones/{zone_name}/records' self._request('POST', path, data=params) def record_delete(self, zone_name, record_id): - path = '/zones/{}/records/{}'.format(zone_name, record_id) + path = f'/zones/{zone_name}/records/{record_id}' self._request('DELETE', path) @@ -102,7 +102,7 @@ class DnsimpleProvider(BaseProvider): 'PTR', 'SPF', 'SRV', 'SSHFP', 'TXT')) def __init__(self, id, token, account, sandbox=False, *args, **kwargs): - self.log = logging.getLogger('DnsimpleProvider[{}]'.format(id)) + self.log = logging.getLogger(f'DnsimpleProvider[{id}]') self.log.debug('__init__: id=%s, token=***, account=%s', id, account) super(DnsimpleProvider, self).__init__(id, *args, **kwargs) self._client = DnsimpleClient(token, account, sandbox) @@ -148,7 +148,7 @@ class DnsimpleProvider(BaseProvider): return { 'ttl': record['ttl'], 'type': _type, - 'value': '{}.'.format(record['content']) + 'value': f'{record["content"]}.' } _data_for_ALIAS = _data_for_CNAME @@ -158,7 +158,7 @@ class DnsimpleProvider(BaseProvider): for record in records: values.append({ 'preference': record['priority'], - 'exchange': '{}.'.format(record['content']) + 'exchange': f'{record["content"]}.' }) return { 'ttl': records[0]['ttl'], @@ -197,7 +197,7 @@ class DnsimpleProvider(BaseProvider): for record in records: content = record['content'] if content[-1] != '.': - content = '{}.'.format(content) + content = f'{content}.' values.append(content) return { 'ttl': records[0]['ttl'], @@ -230,7 +230,7 @@ class DnsimpleProvider(BaseProvider): ) continue - target = '{}.'.format(target) if target != "." else "." + target = f'{target}.' if target != "." else "." values.append({ 'port': port, @@ -296,7 +296,7 @@ class DnsimpleProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -354,8 +354,7 @@ class DnsimpleProvider(BaseProvider): def _params_for_CAA(self, record): for value in record.values: yield { - 'content': '{} {} "{}"'.format(value.flags, value.tag, - value.value), + 'content': f'{value.flags} {value.tag} "{value.value}"', 'name': record.name, 'ttl': record.ttl, 'type': record._type @@ -385,9 +384,8 @@ class DnsimpleProvider(BaseProvider): def _params_for_NAPTR(self, record): for value in record.values: - content = '{} {} "{}" "{}" "{}" {}' \ - .format(value.order, value.preference, value.flags, - value.service, value.regexp, value.replacement) + content = f'{value.order} {value.preference} "{value.flags}" ' \ + f'"{value.service}" "{value.preference}" {value.flags}' yield { 'content': content, 'name': record.name, @@ -398,8 +396,7 @@ class DnsimpleProvider(BaseProvider): def _params_for_SRV(self, record): for value in record.values: yield { - 'content': '{} {} {}'.format(value.weight, value.port, - value.target), + 'content': f'{value.weight} {value.port} {value.target}', 'name': record.name, 'priority': value.priority, 'ttl': record.ttl, @@ -409,9 +406,8 @@ class DnsimpleProvider(BaseProvider): def _params_for_SSHFP(self, record): for value in record.values: yield { - 'content': '{} {} {}'.format(value.algorithm, - value.fingerprint_type, - value.fingerprint), + 'content': f'{value.algorithm} {value.fingerprint_type} ' + f'{value.fingerprint}', 'name': record.name, 'ttl': record.ttl, 'type': record._type @@ -419,7 +415,7 @@ class DnsimpleProvider(BaseProvider): def _apply_Create(self, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self._client.record_create(new.zone.name[:-1], params) @@ -450,7 +446,7 @@ class DnsimpleProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From 4245f6375bf205660e8c4aa05bf0b99854f76ed0 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:34:28 -0700 Subject: [PATCH 10/34] f-strings for DynProvider --- octodns/provider/dyn.py | 48 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/octodns/provider/dyn.py b/octodns/provider/dyn.py index 2fbcadb..53032ea 100644 --- a/octodns/provider/dyn.py +++ b/octodns/provider/dyn.py @@ -142,7 +142,7 @@ class _CachingDynZone(DynZone): return None # this value shouldn't really matter, it's not tied to # whois or anything - hostname = 'hostmaster@{}'.format(zone_name[:-1]) + hostname = f'hostmaster@{zone_name[:-1]}' # Try again with the params necessary to create dyn_zone = _CachingDynZone(zone_name, ttl=3600, contact=hostname, @@ -247,7 +247,7 @@ class DynProvider(BaseProvider): def __init__(self, id, customer, username, password, traffic_directors_enabled=False, *args, **kwargs): - self.log = getLogger('DynProvider[{}]'.format(id)) + self.log = getLogger(f'DynProvider[{id}]') self.log.debug('__init__: id=%s, customer=%s, username=%s, ' 'password=***, traffic_directors_enabled=%s', id, customer, username, traffic_directors_enabled) @@ -429,7 +429,7 @@ class DynProvider(BaseProvider): # problems indicate a malformed ruleset, ignore it continue if ruleset.label.startswith('default:'): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data.update(data_for(_type, record_set.records)) else: # We've stored the geo in label @@ -465,8 +465,8 @@ class DynProvider(BaseProvider): default = {} pools = {} - data_for = getattr(self, '_data_for_{}'.format(_type)) - value_for = getattr(self, '_value_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') + value_for = getattr(self, f'_value_for_{_type}') # Build the list of pools, we can't just read them off of rules b/c we # won't see unused pools there. If/when we dis-allow unused pools we @@ -626,7 +626,7 @@ class DynProvider(BaseProvider): for fqdn, types in self.traffic_directors.items(): for _type, td in types.items(): # Does this TD belong to the current zone - td_zone = '{}.'.format(td.nodes[0]['zone']) + td_zone = f'{td.nodes[0]["zone"]}.' if td_zone != zone.name: # Doesn't belong to the current zone, skip it continue @@ -676,7 +676,7 @@ class DynProvider(BaseProvider): for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data = data_for(_type, records) record = Record.new(zone, name, data, source=self, lenient=lenient) @@ -697,7 +697,7 @@ class DynProvider(BaseProvider): if record in changed or not getattr(record, 'geo', False): # Already changed, or no geo, no need to check it continue - label = '{}:{}'.format(record.fqdn, record._type) + label = f'{record.fqdn}:{record._type}' try: monitor = self.traffic_director_monitors[label] except KeyError: @@ -812,7 +812,7 @@ class DynProvider(BaseProvider): def _traffic_director_monitor(self, record): fqdn = record.fqdn - label = '{}:{}'.format(fqdn, record._type) + label = f'{fqdn}:{record._type}' try: try: monitor = self.traffic_director_monitors[label] @@ -920,14 +920,14 @@ class DynProvider(BaseProvider): continue # And the (sorted) values must match once converted for comparison # purposes - value_for = getattr(self, '_value_for_{}'.format(_type)) + value_for = getattr(self, f'_value_for_{_type}') record_values = [value_for(_type, r) for r in records] if record_values == values: # it's a match return pool # We don't have this pool and thus need to create it - records_for = getattr(self, '_dynamic_records_for_{}'.format(_type)) + records_for = getattr(self, f'_dynamic_records_for_{_type}') records = records_for(values, record_extras) record_set = DSFRecordSet(_type, label, serve_count=1, records=records, dsf_monitor_id=monitor_id) @@ -996,7 +996,7 @@ class DynProvider(BaseProvider): self.log.debug('_mod_geo_rulesets: insert_at=%d', insert_at) # add the default - label = 'default:{}'.format(uuid4().hex) + label = f'default:{uuid4().hex}' ruleset = DSFRuleset(label, 'always', []) ruleset.create(td, index=insert_at) pool = self._find_or_create_geo_pool(td, pools, 'default', new._type, @@ -1026,7 +1026,7 @@ class DynProvider(BaseProvider): 'region': self.REGION_CODES[geo.continent_code] } - label = '{}:{}'.format(geo.code, uuid4().hex) + label = f'{geo.code}:{uuid4().hex}' ruleset = DSFRuleset(label, 'geoip', [], { 'geoip': criteria }) @@ -1068,7 +1068,7 @@ class DynProvider(BaseProvider): new = change.new fqdn = new.fqdn _type = new._type - label = '{}:{}'.format(fqdn, _type) + label = f'{fqdn}:{_type}' node = DSFNode(new.zone.name, fqdn) td = TrafficDirector(label, ttl=new.ttl, nodes=[node], publish='Y') self.log.debug('_mod_geo_Create: td=%s', td.service_id) @@ -1158,7 +1158,7 @@ class DynProvider(BaseProvider): self.log.debug('_mod_dynamic_rulesets: insert_at=%d', insert_at) # Add the base record values as the ultimate/unhealthchecked default - label = 'default:{}'.format(uuid4().hex) + label = f'default:{uuid4().hex}' ruleset = DSFRuleset(label, 'always', []) ruleset.create(td, index=insert_at) # If/when we go beyond A, AAAA, and CNAME this will have to get @@ -1224,7 +1224,7 @@ class DynProvider(BaseProvider): criteria['geoip']['region'] \ .append(self.REGION_CODES[geo['continent_code']]) - label = '{}:{}'.format(rule_num, uuid4().hex) + label = f'{rule_num}:{uuid4().hex}' ruleset = DSFRuleset(label, criteria_type, [], criteria) # Something you have to call create others the constructor does it ruleset.create(td, index=insert_at) @@ -1277,7 +1277,7 @@ class DynProvider(BaseProvider): fqdn = new.fqdn _type = new._type # Create a new traffic director - label = '{}:{}'.format(fqdn, _type) + label = f'{fqdn}:{_type}' node = DSFNode(new.zone.name, fqdn) td = TrafficDirector(label, ttl=new.ttl, nodes=[node], publish='Y') self.log.debug('_mod_dynamic_Create: td=%s', td.service_id) @@ -1335,14 +1335,14 @@ class DynProvider(BaseProvider): def _mod_Create(self, dyn_zone, change): new = change.new - kwargs_for = getattr(self, '_kwargs_for_{}'.format(new._type)) + kwargs_for = getattr(self, f'_kwargs_for_{new._type}') for kwargs in kwargs_for(new): dyn_zone.add_record(new.name, new._type, **kwargs) def _mod_Delete(self, dyn_zone, change): existing = change.existing if existing.name: - target = '{}.{}'.format(existing.name, existing.zone.name[:-1]) + target = f'{existing.name}.{existing.zone.name[:-1]}' else: target = existing.zone.name[:-1] _type = self.TYPE_TO_RECORDS[existing._type] @@ -1361,12 +1361,13 @@ class DynProvider(BaseProvider): # we only mess with changes that have geo info somewhere if getattr(c.new, 'dynamic', False) or getattr(c.existing, 'dynamic', False): - mod = getattr(self, '_mod_dynamic_{}' - .format(c.__class__.__name__)) + klass = c.__class__.__name__ + mod = getattr(self, f'_mod_dynamic_{klass}') mod(dyn_zone, c) elif getattr(c.new, 'geo', False) or getattr(c.existing, 'geo', False): - mod = getattr(self, '_mod_geo_{}'.format(c.__class__.__name__)) + klass = c.__class__.__name__ + mod = getattr(self, f'_mod_geo_{klass}') mod(dyn_zone, c) else: unhandled_changes.append(c) @@ -1376,7 +1377,8 @@ class DynProvider(BaseProvider): def _apply_regular(self, desired, changes, dyn_zone): self.log.debug('_apply_regular: zone=%s', desired.name) for c in changes: - mod = getattr(self, '_mod_{}'.format(c.__class__.__name__)) + klass = c.__class__.__name__ + mod = getattr(self, f'_mod_{klass}') mod(dyn_zone, c) # TODO: detect "extra" changes when monitors are out of date or failover From f8d0f0ad1643efc0260576464ec6dce9f57ec26f Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:35:35 -0700 Subject: [PATCH 11/34] f-strings for EasyDNSProvider --- octodns/provider/easydns.py | 53 +++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/octodns/provider/easydns.py b/octodns/provider/easydns.py index 2ea0c4b..f5c91b4 100644 --- a/octodns/provider/easydns.py +++ b/octodns/provider/easydns.py @@ -50,22 +50,22 @@ class EasyDNSClient(object): def __init__(self, token, api_key, currency, portfolio, sandbox, domain_create_sleep): - self.log = logging.getLogger('EasyDNSProvider[{}]'.format(id)) + self.log = logging.getLogger(f'EasyDNSProvider[{id}]') self.default_currency = currency self.domain_portfolio = portfolio self.domain_create_sleep = domain_create_sleep - auth_key = '{}:{}'.format(token, api_key) + auth_key = f'{token}:{api_key}' auth_key = base64.b64encode(auth_key.encode("utf-8")) + auth_key = auth_key.decode('utf-8') self.base_path = self.SANDBOX if sandbox else self.LIVE sess = Session() - sess.headers.update({'Authorization': 'Basic {}' - .format(auth_key.decode('utf-8'))}) + sess.headers.update({'Authorization': f'Basic {auth_key}'}) sess.headers.update({'accept': 'application/json'}) self._sess = sess def _request(self, method, path, params=None, data=None): - url = '{}{}'.format(self.base_path, path) + url = f'{self.base_path}{path}' resp = self._sess.request(method, url, params=params, json=data) if resp.status_code == 400: self.log.debug('Response code 400, path=%s', path) @@ -80,14 +80,14 @@ class EasyDNSClient(object): return resp def domain(self, name): - path = '/domain/{}'.format(name) + path = f'/domain/{name}' return self._request('GET', path).json() def domain_create(self, name): # EasyDNS allows for new domains to be created for the purpose of DNS # only, or with domain registration. This function creates a DNS only # record expectig the domain to be registered already - path = '/domains/add/{}'.format(name) + path = f'/domains/add/{name}' domain_data = {'service': 'dns', 'term': 1, 'dns_only': 1, @@ -108,9 +108,9 @@ class EasyDNSClient(object): def records(self, zone_name, raw=False): if raw: - path = '/zones/records/all/{}'.format(zone_name) + path = f'/zones/records/all/{zone_name}' else: - path = '/zones/records/parsed/{}'.format(zone_name) + path = f'/zones/records/parsed/{zone_name}' ret = [] resp = self._request('GET', path).json() @@ -123,12 +123,12 @@ class EasyDNSClient(object): # change any apex value to zone name if record['rdata'] == '@': - record['rdata'] = '{}.'.format(zone_name) + record['rdata'] = f'{zone_name}.' return ret def record_create(self, zone_name, params): - path = '/zones/records/add/{}/{}'.format(zone_name, params['type']) + path = f'/zones/records/add/{zone_name}/{params["type"]}' # change empty name string to @, EasyDNS uses @ for apex record names params['host'] = params['name'] if params['host'] == '': @@ -136,7 +136,7 @@ class EasyDNSClient(object): self._request('PUT', path, data=params) def record_delete(self, zone_name, record_id): - path = '/zones/records/{}/{}'.format(zone_name, record_id) + path = f'/zones/records/{zone_name}/{record_id}' self._request('DELETE', path) @@ -164,7 +164,7 @@ class EasyDNSProvider(BaseProvider): def __init__(self, id, token, api_key, currency='CAD', portfolio='myport', sandbox=False, domain_create_sleep=1, *args, **kwargs): - self.log = logging.getLogger('EasyDNSProvider[{}]'.format(id)) + self.log = logging.getLogger(f'EasyDNSProvider[{id}]') self.log.debug('__init__: id=%s, token=***', id) super(EasyDNSProvider, self).__init__(id, *args, **kwargs) self._client = EasyDNSClient(token, api_key, currency, portfolio, @@ -226,7 +226,7 @@ class EasyDNSProvider(BaseProvider): return { 'ttl': record['ttl'], 'type': _type, - 'value': '{}'.format(record['rdata']) + 'value': str(record['rdata']) } def _data_for_MX(self, _type, records): @@ -234,7 +234,7 @@ class EasyDNSProvider(BaseProvider): for record in records: values.append({ 'preference': record['prio'], - 'exchange': '{}'.format(record['rdata']) + 'exchange': str(record['rdata']) }) return { 'ttl': records[0]['ttl'], @@ -245,7 +245,7 @@ class EasyDNSProvider(BaseProvider): def _data_for_NS(self, _type, records): values = [] for record in records: - data = '{}'.format(record['rdata']) + data = str(record['rdata']) values.append(data) return { 'ttl': records[0]['ttl'], @@ -318,7 +318,7 @@ class EasyDNSProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -344,8 +344,7 @@ class EasyDNSProvider(BaseProvider): def _params_for_CAA(self, record): for value in record.values: yield { - 'rdata': "{} {} {}".format(value.flags, value.tag, - value.value), + 'rdata': f"{value.flags} {value.tag} {value.value}", 'name': record.name, 'ttl': record.ttl, 'type': record._type @@ -353,12 +352,8 @@ class EasyDNSProvider(BaseProvider): def _params_for_NAPTR(self, record): for value in record.values: - content = '{} {} "{}" "{}" "{}" {}'.format(value.order, - value.preference, - value.flags, - value.service, - value.regexp, - value.replacement) + content = f'{value.order} {value.preference} "{value.flags}" ' \ + f'"{value.service}" "{value.regexp}" {value.replacement}' yield { 'rdata': content, 'name': record.name, @@ -389,8 +384,8 @@ class EasyDNSProvider(BaseProvider): def _params_for_SRV(self, record): for value in record.values: yield { - 'rdata': "{} {} {} {}".format(value.priority, value.port, - value.weight, value.target), + 'rdata': f"{value.priority} {value.port} {value.weight} " + f"{value.target}", 'name': record.name, 'ttl': record.ttl, 'type': record._type, @@ -407,7 +402,7 @@ class EasyDNSProvider(BaseProvider): def _apply_Create(self, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self._client.record_create(new.zone.name[:-1], params) @@ -440,7 +435,7 @@ class EasyDNSProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From 4be12860d521748efb545d2ccaa9bc18b886d703 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:36:27 -0700 Subject: [PATCH 12/34] f-strings for EtcHostsProvider --- octodns/provider/etc_hosts.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/octodns/provider/etc_hosts.py b/octodns/provider/etc_hosts.py index b143fdf..65e9f4f 100644 --- a/octodns/provider/etc_hosts.py +++ b/octodns/provider/etc_hosts.py @@ -29,7 +29,7 @@ class EtcHostsProvider(BaseProvider): SUPPORTS = set(('A', 'AAAA', 'ALIAS', 'CNAME')) def __init__(self, id, directory, *args, **kwargs): - self.log = logging.getLogger('EtcHostsProvider[{}]'.format(id)) + self.log = logging.getLogger(f'EtcHostsProvider[{id}]') self.log.debug('__init__: id=%s, directory=%s', id, directory) super(EtcHostsProvider, self).__init__(id, *args, **kwargs) self.directory = directory @@ -67,24 +67,25 @@ class EtcHostsProvider(BaseProvider): if not isdir(self.directory): makedirs(self.directory) - filename = '{}hosts'.format(path.join(self.directory, desired.name)) + filepath = path.join(self.directory, desired.name) + filename = f'{filepath}hosts' self.log.info('_apply: filename=%s', filename) with open(filename, 'w') as fh: fh.write('##################################################\n') - fh.write('# octoDNS {} {}\n'.format(self.id, desired.name)) + fh.write(f'# octoDNS {self.id} {desired.name}\n') fh.write('##################################################\n\n') if values: fh.write('## A & AAAA\n\n') for fqdn, value in sorted(values.items()): if fqdn[0] == '*': fh.write('# ') - fh.write('{}\t{}\n\n'.format(value, fqdn)) + fh.write(f'{value}\t{fqdn}\n\n') if cnames: fh.write('\n## CNAME (mapped)\n\n') for fqdn, value in sorted(cnames.items()): # Print out a comment of the first level - fh.write('# {} -> {}\n'.format(fqdn, value)) + fh.write(f'# {fqdn} -> {value}\n') seen = set() while True: seen.add(value) @@ -92,7 +93,7 @@ class EtcHostsProvider(BaseProvider): value = values[value] # If we're here we've found the target, print it # and break the loop - fh.write('{}\t{}\n'.format(value, fqdn)) + fh.write(f'{value}\t{fqdn}\n') break except KeyError: # Try and step down one level @@ -102,15 +103,13 @@ class EtcHostsProvider(BaseProvider): if value: if value in seen: # We'd loop here, break it - fh.write('# {} -> {} **loop**\n' - .format(orig, value)) + fh.write(f'# {orig} -> {value} **loop**\n') break else: - fh.write('# {} -> {}\n' - .format(orig, value)) + fh.write(f'# {orig} -> {value}\n') else: # Don't have anywhere else to go - fh.write('# {} -> **unknown**\n'.format(orig)) + fh.write(f'# {orig} -> **unknown**\n') break fh.write('\n') From 35c0ff4d8e9d29e0f80609c1f6daec6b82698f06 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 08:37:48 -0700 Subject: [PATCH 13/34] f-strings for DnsMadeEasyProvider --- octodns/provider/dnsmadeeasy.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/octodns/provider/dnsmadeeasy.py b/octodns/provider/dnsmadeeasy.py index ddd40d2..9aab39c 100644 --- a/octodns/provider/dnsmadeeasy.py +++ b/octodns/provider/dnsmadeeasy.py @@ -24,9 +24,8 @@ class DnsMadeEasyClientException(ProviderException): class DnsMadeEasyClientBadRequest(DnsMadeEasyClientException): def __init__(self, resp): - errors = resp.json()['error'] - super(DnsMadeEasyClientBadRequest, self).__init__( - '\n - {}'.format('\n - '.join(errors))) + errors = '\n - '.join(resp.json()['error']) + super(DnsMadeEasyClientBadRequest, self).__init__(f'\n - {errors}') class DnsMadeEasyClientUnauthorized(DnsMadeEasyClientException): @@ -71,7 +70,7 @@ class DnsMadeEasyClient(object): 'x-dnsme-requestDate': now } - url = '{}{}'.format(self._base, path) + url = f'{self._base}{path}' resp = self._sess.request(method, url, headers=headers, params=params, json=data) if resp.status_code == 400: @@ -93,12 +92,12 @@ class DnsMadeEasyClient(object): resp = self._request('GET', '/').json() zones += resp['data'] - self._domains = {'{}.'.format(z['name']): z['id'] for z in zones} + self._domains = {f'{z["name"]}.': z['id'] for z in zones} return self._domains def domain(self, name): - path = '/id/{}'.format(name) + path = f'/id/{name}' return self._request('GET', path).json() def domain_create(self, name): @@ -106,7 +105,7 @@ class DnsMadeEasyClient(object): def records(self, zone_name): zone_id = self.domains.get(zone_name, False) - path = '/{}/records'.format(zone_id) + path = f'/{zone_id}/records' ret = [] # has pages in resp, do we need paging? @@ -124,13 +123,13 @@ class DnsMadeEasyClient(object): if value == '': record['value'] = zone_name elif not value.endswith('.'): - record['value'] = '{}.{}'.format(value, zone_name) + record['value'] = f'{value}.{zone_name}' return ret def record_create(self, zone_name, params): zone_id = self.domains.get(zone_name, False) - path = '/{}/records'.format(zone_id) + path = f'/{zone_id}/records' # change ALIAS records to ANAME if params['type'] == 'ALIAS': @@ -140,7 +139,7 @@ class DnsMadeEasyClient(object): def record_delete(self, zone_name, record_id): zone_id = self.domains.get(zone_name, False) - path = '/{}/records/{}'.format(zone_id, record_id) + path = f'/{zone_id}/records/{record_id}' self._request('DELETE', path) @@ -165,7 +164,7 @@ class DnsMadeEasyProvider(BaseProvider): def __init__(self, id, api_key, secret_key, sandbox=False, ratelimit_delay=0.0, *args, **kwargs): - self.log = logging.getLogger('DnsMadeEasyProvider[{}]'.format(id)) + self.log = logging.getLogger(f'DnsMadeEasyProvider[{id}]') self.log.debug('__init__: id=%s, api_key=***, secret_key=***, ' 'sandbox=%s', id, sandbox) super(DnsMadeEasyProvider, self).__init__(id, *args, **kwargs) @@ -275,7 +274,7 @@ class DnsMadeEasyProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -385,7 +384,7 @@ class DnsMadeEasyProvider(BaseProvider): def _apply_Create(self, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self._client.record_create(new.zone.name, params) @@ -416,7 +415,7 @@ class DnsMadeEasyProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From ac31bcaa1131a6566a5b69d6a0de6de16bc2fa86 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:05:31 -0700 Subject: [PATCH 14/34] f-strings for AkamaiProvider --- octodns/provider/edgedns.py | 41 +++++++++++++++---------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/octodns/provider/edgedns.py b/octodns/provider/edgedns.py index 1dde770..aa546be 100644 --- a/octodns/provider/edgedns.py +++ b/octodns/provider/edgedns.py @@ -59,34 +59,34 @@ class AkamaiClient(object): return resp def record_create(self, zone, name, record_type, content): - path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type) + path = f'zones/{zone}/names/{name}/types/{record_type}' result = self._request('POST', path, data=content) return result def record_delete(self, zone, name, record_type): - path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type) + path = f'zones/{zone}/names/{name}/types/{record_type}' result = self._request('DELETE', path) return result def record_replace(self, zone, name, record_type, content): - path = 'zones/{}/names/{}/types/{}'.format(zone, name, record_type) + path = f'zones/{zone}/names/{name}/types/{record_type}' result = self._request('PUT', path, data=content) return result def zone_get(self, zone): - path = 'zones/{}'.format(zone) + path = f'zones/{zone}' result = self._request('GET', path) return result def zone_create(self, contractId, params, gid=None): - path = 'zones?contractId={}'.format(contractId) + path = f'zones?contractId={contractId}' if gid is not None: - path += '&gid={}'.format(gid) + path += f'&gid={gid}' result = self._request('POST', path, data=params) @@ -104,7 +104,7 @@ class AkamaiClient(object): 'types': types } - path = 'zones/{}/recordsets'.format(zone) + path = f'zones/{zone}/recordsets' result = self._request('GET', path, params=params) return result @@ -167,7 +167,7 @@ class AkamaiProvider(BaseProvider): def __init__(self, id, client_secret, host, access_token, client_token, contract_id=None, gid=None, *args, **kwargs): - self.log = getLogger('AkamaiProvider[{}]'.format(id)) + self.log = getLogger(f'AkamaiProvider[{id}]') self.log.debug('__init__: id=%s, ') super(AkamaiProvider, self).__init__(id, *args, **kwargs) @@ -212,7 +212,7 @@ class AkamaiProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records[0]), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -239,7 +239,7 @@ class AkamaiProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) @@ -249,7 +249,7 @@ class AkamaiProvider(BaseProvider): new = change.new record_type = new._type - params_for = getattr(self, '_params_for_{}'.format(record_type)) + params_for = getattr(self, f'_params_for_{record_type}') values = self._get_values(new.data) rdata = params_for(values) @@ -282,7 +282,7 @@ class AkamaiProvider(BaseProvider): new = change.new record_type = new._type - params_for = getattr(self, '_params_for_{}'.format(record_type)) + params_for = getattr(self, f'_params_for_{record_type}') values = self._get_values(new.data) rdata = params_for(values) @@ -316,7 +316,7 @@ class AkamaiProvider(BaseProvider): def _data_for_CNAME(self, _type, records): value = records['rdata'][0] if (value[-1] != '.'): - value = '{}.'.format(value) + value = f'{value}.' return { 'ttl': records['ttl'], @@ -429,9 +429,7 @@ class AkamaiProvider(BaseProvider): for r in values: preference = r['preference'] exchange = r['exchange'] - - record = '{} {}'.format(preference, exchange) - rdata.append(record) + rdata.append(f'{preference} {exchange}') return rdata @@ -445,9 +443,7 @@ class AkamaiProvider(BaseProvider): srvc = "\"" + r['service'] + "\"" rgx = "\"" + r['regexp'] + "\"" rpl = r['replacement'] - - record = '{} {} {} {} {} {}'.format(ordr, prf, flg, srvc, rgx, rpl) - rdata.append(record) + rdata.append(f'{ordr} {prf} {flg} {srvc} {rgx} {rpl}') return rdata @@ -467,9 +463,7 @@ class AkamaiProvider(BaseProvider): weight = r['weight'] port = r['port'] target = r['target'] - - record = '{} {} {} {}'.format(priority, weight, port, target) - rdata.append(record) + rdata.append(f'{priority} {weight} {port} {target}') return rdata @@ -480,8 +474,7 @@ class AkamaiProvider(BaseProvider): fp_type = r['fingerprint_type'] fp = r['fingerprint'] - record = '{} {} {}'.format(algorithm, fp_type, fp) - rdata.append(record) + rdata.append(f'{algorithm} {fp_type} {fp}') return rdata From 7b5593a2ee9dbbdc5cb0d5934a2e5aed629928a4 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:06:33 -0700 Subject: [PATCH 15/34] f-strings for GandiProvider --- octodns/provider/gandi.py | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/octodns/provider/gandi.py b/octodns/provider/gandi.py index 0938ac9..b1c4082 100644 --- a/octodns/provider/gandi.py +++ b/octodns/provider/gandi.py @@ -52,12 +52,12 @@ class GandiClient(object): def __init__(self, token): session = Session() - session.headers.update({'Authorization': 'Apikey {}'.format(token)}) + session.headers.update({'Authorization': f'Apikey {token}'}) self._session = session self.endpoint = 'https://api.gandi.net/v5' def _request(self, method, path, params={}, data=None): - url = '{}{}'.format(self.endpoint, path) + url = f'{self.endpoint}{path}' r = self._session.request(method, url, params=params, json=data) if r.status_code == 400: raise GandiClientBadRequest(r) @@ -71,8 +71,7 @@ class GandiClient(object): return r def zone(self, zone_name): - return self._request('GET', '/livedns/domains/{}' - .format(zone_name)).json() + return self._request('GET', f'/livedns/domains/{zone_name}').json() def zone_create(self, zone_name): return self._request('POST', '/livedns/domains', data={ @@ -81,8 +80,8 @@ class GandiClient(object): }).json() def zone_records(self, zone_name): - records = self._request('GET', '/livedns/domains/{}/records' - .format(zone_name)).json() + records = self._request('GET', + f'/livedns/domains/{zone_name}/records').json() for record in records: if record['rrset_name'] == '@': @@ -93,18 +92,17 @@ class GandiClient(object): 'NS', 'SRV']: for i, value in enumerate(record['rrset_values']): if not value.endswith('.'): - record['rrset_values'][i] = '{}.{}.'.format( - value, zone_name) + record['rrset_values'][i] = f'{value}.{zone_name}.' return records def record_create(self, zone_name, data): - self._request('POST', '/livedns/domains/{}/records'.format(zone_name), + self._request('POST', f'/livedns/domains/{zone_name}/records', data=data) def record_delete(self, zone_name, record_name, record_type): - self._request('DELETE', '/livedns/domains/{}/records/{}/{}' - .format(zone_name, record_name, record_type)) + self._request('DELETE', f'/livedns/domains/{zone_name}/records/' + f'{record_name}/{record_type}') class GandiProvider(BaseProvider): @@ -123,7 +121,7 @@ class GandiProvider(BaseProvider): 'MX', 'NS', 'PTR', 'SPF', 'SRV', 'SSHFP', 'TXT'])) def __init__(self, id, token, *args, **kwargs): - self.log = logging.getLogger('GandiProvider[{}]'.format(id)) + self.log = logging.getLogger(f'GandiProvider[{id}]') self.log.debug('__init__: id=%s, token=***', id) super(GandiProvider, self).__init__(id, *args, **kwargs) self._client = GandiClient(token) @@ -246,7 +244,7 @@ class GandiProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -280,7 +278,7 @@ class GandiProvider(BaseProvider): 'rrset_name': self._record_name(record.name), 'rrset_ttl': record.ttl, 'rrset_type': record._type, - 'rrset_values': ['{} {} "{}"'.format(v.flags, v.tag, v.value) + 'rrset_values': [f'{v.flags} {v.tag} "{v.value}"' for v in record.values] } @@ -302,7 +300,7 @@ class GandiProvider(BaseProvider): 'rrset_name': self._record_name(record.name), 'rrset_ttl': record.ttl, 'rrset_type': record._type, - 'rrset_values': ['{} {}'.format(v.preference, v.exchange) + 'rrset_values': [f'{v.preference} {v.exchange}' for v in record.values] } @@ -311,8 +309,8 @@ class GandiProvider(BaseProvider): 'rrset_name': self._record_name(record.name), 'rrset_ttl': record.ttl, 'rrset_type': record._type, - 'rrset_values': ['{} {} {} {}'.format(v.priority, v.weight, v.port, - v.target) for v in record.values] + 'rrset_values': [f'{v.priority} {v.weight} {v.port} {v.target}' + for v in record.values] } def _params_for_SSHFP(self, record): @@ -320,13 +318,13 @@ class GandiProvider(BaseProvider): 'rrset_name': self._record_name(record.name), 'rrset_ttl': record.ttl, 'rrset_type': record._type, - 'rrset_values': ['{} {} {}'.format(v.algorithm, v.fingerprint_type, - v.fingerprint) for v in record.values] + 'rrset_values': [f'{v.algorithm} {v.fingerprint_type} ' + f'{v.fingerprint}' for v in record.values] } def _apply_create(self, change): new = change.new - data = getattr(self, '_params_for_{}'.format(new._type))(new) + data = getattr(self, f'_params_for_{new._type}')(new) self._client.record_create(new.zone.name[:-1], data) def _apply_update(self, change): @@ -373,7 +371,7 @@ class GandiProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name.lower()))(change) + getattr(self, f'_apply_{class_name.lower()}')(change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From 0556532e98709347558fc29ec7fb49211438cd9a Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:08:24 -0700 Subject: [PATCH 16/34] f-strings for GoogleCloudProvider --- octodns/provider/googlecloud.py | 40 ++++++++++++++------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/octodns/provider/googlecloud.py b/octodns/provider/googlecloud.py index b9999d6..9d424f0 100644 --- a/octodns/provider/googlecloud.py +++ b/octodns/provider/googlecloud.py @@ -54,7 +54,7 @@ class GoogleCloudProvider(BaseProvider): self.gcloud_client = dns.Client(project=project) # Logger - self.log = getLogger('GoogleCloudProvider[{}]'.format(id)) + self.log = getLogger(f'GoogleCloudProvider[{id}]') self.id = id self._gcloud_zones = {} @@ -85,8 +85,7 @@ class GoogleCloudProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - _rrset_func = getattr( - self, '_rrset_for_{}'.format(change.record._type)) + _rrset_func = getattr(self, f'_rrset_for_{change.record._type}') if class_name == 'Create': gcloud_changes.add_record_set( @@ -100,9 +99,9 @@ class GoogleCloudProvider(BaseProvider): gcloud_changes.add_record_set( _rrset_func(gcloud_zone, change.new)) else: - raise RuntimeError('Change type "{}" for change "{!s}" ' - 'is none of "Create", "Delete" or "Update' - .format(class_name, change)) + msg = f'Change type "{class_name}" for change ' \ + f'"{str(change)}" is none of "Create", "Delete" or "Update' + raise RuntimeError(msg) gcloud_changes.create() @@ -116,8 +115,8 @@ class GoogleCloudProvider(BaseProvider): time.sleep(self.CHANGE_LOOP_WAIT) if gcloud_changes.status != 'done': - raise RuntimeError("Timeout reached after {} seconds".format( - i * self.CHANGE_LOOP_WAIT)) + timeout = i * self.CHANGE_LOOP_WAIT + raise RuntimeError(f"Timeout reached after {timeout} seconds") def _create_gcloud_zone(self, dns_name): """Creates a google cloud ManagedZone with dns_name, and zone named @@ -131,8 +130,7 @@ class GoogleCloudProvider(BaseProvider): # Zone name must begin with a letter, end with a letter or digit, # and only contain lowercase letters, digits or dashes, # and be 63 characters or less - zone_name = 'zone-{}-{}'.format( - dns_name.replace('.', '-'), uuid4().hex)[:63] + zone_name = f'zone-{dns_name.replace(".", "-")}-{uuid4().hex}'[:63] gcloud_zone = self.gcloud_client.zone( name=zone_name, @@ -143,7 +141,7 @@ class GoogleCloudProvider(BaseProvider): # add this new zone to the list of zones. self._gcloud_zones[gcloud_zone.dns_name] = gcloud_zone - self.log.info("Created zone {}. Fqdn {}.".format(zone_name, dns_name)) + self.log.info(f"Created zone {zone_name}. Fqdn {dns_name}.") return gcloud_zone @@ -224,12 +222,12 @@ class GoogleCloudProvider(BaseProvider): # which is also the way octodns likes it. record_name = record_name[:-(len(zone.name) + 1)] typ = gcloud_record.record_type.upper() - data = getattr(self, '_data_for_{}'.format(typ)) + data = getattr(self, f'_data_for_{typ}') data = data(gcloud_record) data['type'] = typ data['ttl'] = gcloud_record.ttl - self.log.debug('populate: adding record {} records: {!s}' - .format(record_name, data)) + self.log.debug('populate: adding record %s records: %s', + record_name, data) record = Record.new(zone, record_name, data, source=self) zone.add_record(record, lenient=lenient) @@ -306,8 +304,7 @@ class GoogleCloudProvider(BaseProvider): def _rrset_for_CAA(self, gcloud_zone, record): return gcloud_zone.resource_record_set( record.fqdn, record._type, record.ttl, [ - '{} {} {}'.format(v.flags, v.tag, v.value) - for v in record.values]) + f'{v.flags} {v.tag} {v.value}' for v in record.values]) def _rrset_for_CNAME(self, gcloud_zone, record): return gcloud_zone.resource_record_set( @@ -316,15 +313,13 @@ class GoogleCloudProvider(BaseProvider): def _rrset_for_MX(self, gcloud_zone, record): return gcloud_zone.resource_record_set( record.fqdn, record._type, record.ttl, [ - '{} {}'.format(v.preference, v.exchange) - for v in record.values]) + f'{v.preference} {v.exchange}' for v in record.values]) def _rrset_for_NAPTR(self, gcloud_zone, record): return gcloud_zone.resource_record_set( record.fqdn, record._type, record.ttl, [ - '{} {} "{}" "{}" "{}" {}'.format( - v.order, v.preference, v.flags, v.service, - v.regexp, v.replacement) for v in record.values]) + f'{v.order} {v.preference} "{v.flags}" "{v.service}" ' + f'"{v.regexp}" {v.replacement}' for v in record.values]) _rrset_for_NS = _rrset_for_A @@ -337,8 +332,7 @@ class GoogleCloudProvider(BaseProvider): def _rrset_for_SRV(self, gcloud_zone, record): return gcloud_zone.resource_record_set( record.fqdn, record._type, record.ttl, [ - '{} {} {} {}' - .format(v.priority, v.weight, v.port, v.target) + f'{v.priority} {v.weight} {v.port} {v.target}' for v in record.values]) _rrset_for_TXT = _rrset_for_SPF From a31e4b91b722d2c85d372185c81176705ed9104b Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:09:56 -0700 Subject: [PATCH 17/34] f-strings for GCoreProvider --- octodns/provider/gcore.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/octodns/provider/gcore.py b/octodns/provider/gcore.py index b76f90e..10fd612 100644 --- a/octodns/provider/gcore.py +++ b/octodns/provider/gcore.py @@ -55,12 +55,12 @@ class GCoreClient(object): self._api_url = api_url if token is not None and token_type is not None: self._session.headers.update( - {"Authorization": "{} {}".format(token_type, token)} + {"Authorization": f"{token_type} {token}"} ) elif login is not None and password is not None: token = self._auth(auth_url, login, password) self._session.headers.update( - {"Authorization": "Bearer {}".format(token)} + {"Authorization": f"Bearer {token}"} ) else: raise ValueError("either token or login & password must be set") @@ -107,15 +107,9 @@ class GCoreClient(object): ).json() def zone_records(self, zone_name): - rrsets = self._request( - "GET", - "{}".format( - self._build_url( - self._api_url, self.ROOT_ZONES, zone_name, "rrsets" - ) - ), - params={"all": "true"}, - ).json() + url = self._build_url(self._api_url, self.ROOT_ZONES, zone_name, + "rrsets") + rrsets = self._request("GET", url, params={"all": "true"}).json() records = rrsets["rrsets"] return records @@ -174,7 +168,7 @@ class GCoreProvider(BaseProvider): api_url = kwargs.pop("url", "https://dnsapi.gcorelabs.com/v2") auth_url = kwargs.pop("auth_url", "https://api.gcdn.co") self.records_per_response = kwargs.pop("records_per_response", 1) - self.log = logging.getLogger("GCoreProvider[{}]".format(id)) + self.log = logging.getLogger(f"GCoreProvider[{id}]") self.log.debug("__init__: id=%s", id) super(GCoreProvider, self).__init__(id, *args, **kwargs) self._client = GCoreClient( @@ -188,7 +182,7 @@ class GCoreProvider(BaseProvider): ) def _add_dot_if_need(self, value): - return "{}.".format(value) if not value.endswith(".") else value + return f"{value}." if not value.endswith(".") else value def _build_pools(self, record, default_pool_name, value_transform_fn): defaults = [] @@ -215,7 +209,7 @@ class GCoreProvider(BaseProvider): [GeoCodes.country_to_code(cc.upper()) for cc in countries] ) | frozenset(cc.upper() for cc in continents) if geo_set not in geo_sets: - geo_sets[geo_set] = "pool-{}".format(pool_idx) + geo_sets[geo_set] = f"pool-{pool_idx}" pool_idx += 1 pools[geo_sets[geo_set]]["values"].append(value) @@ -247,9 +241,7 @@ class GCoreProvider(BaseProvider): ) if len(pools) == 0: raise RuntimeError( - "filter is enabled, but no pools where built for {}".format( - record - ) + f"filter is enabled, but no pools where built for {record}" ) # defaults can't be empty, so use first pool values @@ -402,7 +394,7 @@ class GCoreProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, record in types.items(): - data_for = getattr(self, "_data_for_{}".format(_type)) + data_for = getattr(self, f"_data_for_{_type}") record = Record.new( zone, name, @@ -582,7 +574,7 @@ class GCoreProvider(BaseProvider): def _apply_create(self, change): self.log.info("creating: %s", change) new = change.new - data = getattr(self, "_params_for_{}".format(new._type))(new) + data = getattr(self, f"_params_for_{new._type}")(new) self._client.record_create( new.zone.name[:-1], new.fqdn, new._type, data ) @@ -590,7 +582,7 @@ class GCoreProvider(BaseProvider): def _apply_update(self, change): self.log.info("updating: %s", change) new = change.new - data = getattr(self, "_params_for_{}".format(new._type))(new) + data = getattr(self, f"_params_for_{new._type}")(new) self._client.record_update( new.zone.name[:-1], new.fqdn, new._type, data ) @@ -621,4 +613,4 @@ class GCoreProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, "_apply_{}".format(class_name.lower()))(change) + getattr(self, f"_apply_{class_name.lower()}")(change) From fe49ed9d3bc62ce4cdbae703486a087defe74e63 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:10:48 -0700 Subject: [PATCH 18/34] f-strings for HetznerProvider --- octodns/provider/hetzner.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/octodns/provider/hetzner.py b/octodns/provider/hetzner.py index b1b2884..9e4db44 100644 --- a/octodns/provider/hetzner.py +++ b/octodns/provider/hetzner.py @@ -39,7 +39,7 @@ class HetznerClient(object): self._session = session def _do(self, method, path, params=None, data=None): - url = '{}{}'.format(self.BASE_URL, path) + url = f'{self.BASE_URL}{path}' response = self._session.request(method, url, params=params, json=data) if response.status_code == 401: raise HetznerClientUnauthorized() @@ -73,7 +73,7 @@ class HetznerClient(object): self._do('POST', '/records', data=data) def zone_record_delete(self, zone_id, record_id): - self._do('DELETE', '/records/{}'.format(record_id)) + self._do('DELETE', f'/records/{record_id}') class HetznerProvider(BaseProvider): @@ -90,7 +90,7 @@ class HetznerProvider(BaseProvider): SUPPORTS = set(('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'SRV', 'TXT')) def __init__(self, id, token, *args, **kwargs): - self.log = logging.getLogger('HetznerProvider[{}]'.format(id)) + self.log = logging.getLogger(f'HetznerProvider[{id}]') self.log.debug('__init__: id=%s, token=***', id) super(HetznerProvider, self).__init__(id, *args, **kwargs) self._client = HetznerClient(token) @@ -102,7 +102,7 @@ class HetznerProvider(BaseProvider): def _append_dot(self, value): if value == '@' or value[-1] == '.': return value - return '{}.'.format(value) + return f'{value}.' def zone_metadata(self, zone_id=None, zone_name=None): if zone_name is not None: @@ -232,7 +232,7 @@ class HetznerProvider(BaseProvider): before = len(zone.records) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -256,7 +256,7 @@ class HetznerProvider(BaseProvider): def _params_for_CAA(self, record): for value in record.values: - data = '{} {} "{}"'.format(value.flags, value.tag, value.value) + data = f'{value.flags} {value.tag} "{value.value}"' yield { 'value': data, 'name': record.name, @@ -276,7 +276,7 @@ class HetznerProvider(BaseProvider): def _params_for_MX(self, record): for value in record.values: - data = '{} {}'.format(value.preference, value.exchange) + data = f'{value.preference} {value.exchange}' yield { 'value': data, 'name': record.name, @@ -288,8 +288,8 @@ class HetznerProvider(BaseProvider): def _params_for_SRV(self, record): for value in record.values: - data = '{} {} {} {}'.format(value.priority, value.weight, - value.port, value.target) + data = f'{value.priority} {value.weight} {value.port} ' \ + f'{value.target}' yield { 'value': data, 'name': record.name, @@ -301,7 +301,7 @@ class HetznerProvider(BaseProvider): def _apply_Create(self, zone_id, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self._client.zone_record_create(zone_id, params['name'], params['type'], params['value'], @@ -334,7 +334,7 @@ class HetznerProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(zone_id, change) + getattr(self, f'_apply_{class_name}')(zone_id, change) # Clear out the cache if any self._zone_records.pop(desired.name, None) From 4ab3238f247a13ce0c2510c46b817daabc72a154 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:45:14 -0700 Subject: [PATCH 19/34] f-strings for MythicBeastsProvider --- octodns/provider/mythicbeasts.py | 66 +++++++++++++++----------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/octodns/provider/mythicbeasts.py b/octodns/provider/mythicbeasts.py index 683209d..7cc820e 100644 --- a/octodns/provider/mythicbeasts.py +++ b/octodns/provider/mythicbeasts.py @@ -38,9 +38,7 @@ def remove_trailing_dot(value): class MythicBeastsUnauthorizedException(ProviderException): def __init__(self, zone, *args): self.zone = zone - self.message = 'Mythic Beasts unauthorized for zone: {}'.format( - self.zone - ) + self.message = f'Mythic Beasts unauthorized for zone: {self.zone}' super(MythicBeastsUnauthorizedException, self).__init__( self.message, self.zone, *args) @@ -50,10 +48,8 @@ class MythicBeastsRecordException(ProviderException): def __init__(self, zone, command, *args): self.zone = zone self.command = command - self.message = 'Mythic Beasts could not action command: {} {}'.format( - self.zone, - self.command, - ) + self.message = 'Mythic Beasts could not action command: ' \ + f'{self.zone} {self.command}' super(MythicBeastsRecordException, self).__init__( self.message, self.zone, self.command, *args) @@ -108,7 +104,7 @@ class MythicBeastsProvider(BaseProvider): BASE = 'https://dnsapi.mythic-beasts.com/' def __init__(self, identifier, passwords, *args, **kwargs): - self.log = getLogger('MythicBeastsProvider[{}]'.format(identifier)) + self.log = getLogger(f'MythicBeastsProvider[{identifier}]') assert isinstance(passwords, dict), 'Passwords must be a dictionary' @@ -147,11 +143,12 @@ class MythicBeastsProvider(BaseProvider): return self._request('POST', self.BASE, data=data) def records(self, zone): - assert zone in self._passwords, 'Missing password for domain: {}' \ - .format(remove_trailing_dot(zone)) + domain = remove_trailing_dot(zone) + assert zone in self._passwords, \ + f'Missing password for domain: {domain}' return self._post({ - 'domain': remove_trailing_dot(zone), + 'domain': domain, 'password': self._passwords[zone], 'showall': 0, 'command': 'LIST', @@ -202,7 +199,7 @@ class MythicBeastsProvider(BaseProvider): exchange = match.group('exchange') if not exchange.endswith('.'): - exchange = '{}.{}'.format(exchange, data['zone']) + exchange = f'{exchange}.{data["zone"]}' values.append({ 'preference': match.group('preference'), @@ -220,7 +217,7 @@ class MythicBeastsProvider(BaseProvider): ttl = data['raw_values'][0]['ttl'] value = data['raw_values'][0]['value'] if not value.endswith('.'): - value = '{}.{}'.format(value, data['zone']) + value = f'{value}.{data["zone"]}' return MythicBeastsProvider._data_for_single( _type, @@ -252,7 +249,7 @@ class MythicBeastsProvider(BaseProvider): target = match.group('target') if not target.endswith('.'): - target = '{}.{}'.format(target, data['zone']) + target = f'{target}.{data["zone"]}' values.append({ 'priority': match.group('priority'), @@ -344,7 +341,7 @@ class MythicBeastsProvider(BaseProvider): _ttl = int(match.group('ttl')) _value = match.group('value').strip() - if hasattr(self, '_data_for_{}'.format(_type)): + if hasattr(self, f'_data_for_{_type}'): if _name not in data[_type]: data[_type][_name] = { 'raw_values': [{'value': _value, 'ttl': _ttl}], @@ -361,7 +358,7 @@ class MythicBeastsProvider(BaseProvider): for _type in data: for _name in data[_type]: - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new( zone, @@ -391,7 +388,7 @@ class MythicBeastsProvider(BaseProvider): else: values = [record.value] - base = '{} {} {} {}'.format(action, hostname, ttl, _type) + base = f'{action} {hostname} {ttl} {_type}' # Unescape TXT records if _type == 'TXT': @@ -400,35 +397,32 @@ class MythicBeastsProvider(BaseProvider): # Handle specific types or default if _type == 'SSHFP': data = values[0].data - commands.append('{} {} {} {}'.format( - base, - data['algorithm'], - data['fingerprint_type'], - data['fingerprint'] - )) + algorithm = data['algorithm'] + fingerprint_type = data['fingerprint_type'] + fingerprint = data['fingerprint'] + commands.append(f'{base} {algorithm} {fingerprint_type} ' + f'{fingerprint}') elif _type == 'SRV': for value in values: data = value.data - commands.append('{} {} {} {} {}'.format( - base, - data['priority'], - data['weight'], - data['port'], - data['target'])) + priority = data['priority'] + weight = data['weight'] + port = data['port'] + target = data['target'] + commands.append(f'{base} {priority} {weight} {port} {target}') elif _type == 'MX': for value in values: data = value.data - commands.append('{} {} {}'.format( - base, - data['preference'], - data['exchange'])) + preference = data['preference'] + exchange = data['exchange'] + commands.append(f'{base} {preference} {exchange}') else: - if hasattr(self, '_data_for_{}'.format(_type)): + if hasattr(self, f'_data_for_{_type}'): for value in values: - commands.append('{} {}'.format(base, value)) + commands.append(f'{base} {value}') else: self.log.debug('skipping %s as not supported', _type) @@ -472,4 +466,4 @@ class MythicBeastsProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) From b29c27df7c1f87337dda9f21b0b0a16a1740c3c6 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 17:45:32 -0700 Subject: [PATCH 20/34] Fix BaseProvider test call expect --- tests/test_octodns_provider_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_octodns_provider_base.py b/tests/test_octodns_provider_base.py index cee7c2c..fd46753 100644 --- a/tests/test_octodns_provider_base.py +++ b/tests/test_octodns_provider_base.py @@ -461,7 +461,7 @@ class TestBaseProvider(TestCase): normal.supports_warn_or_except('Hello World!', 'Goodbye') normal.log.warning.assert_called_once() normal.log.warning.assert_has_calls([ - call('Hello World!; Goodbye') + call('%s; %s', 'Hello World!', 'Goodbye') ]) strict = MinimalProvider(strict_supports=True) From 4ca8cded8b26d006cd58bb6e7c4f66dcd76c6c35 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:04:40 -0700 Subject: [PATCH 21/34] f-strings for Ns1Provider --- octodns/provider/ns1.py | 53 +++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/octodns/provider/ns1.py b/octodns/provider/ns1.py index 8c09f39..e6fab6e 100644 --- a/octodns/provider/ns1.py +++ b/octodns/provider/ns1.py @@ -22,7 +22,7 @@ from .base import BaseProvider def _ensure_endswith_dot(string): - return string if string.endswith('.') else '{}.'.format(string) + return string if string.endswith('.') else f'{string}.' class Ns1Exception(ProviderException): @@ -445,7 +445,7 @@ class Ns1Provider(BaseProvider): def __init__(self, id, api_key, retry_count=4, monitor_regions=None, parallelism=None, client_config=None, shared_notifylist=False, *args, **kwargs): - self.log = getLogger('Ns1Provider[{}]'.format(id)) + self.log = getLogger(f'Ns1Provider[{id}]') self.log.debug('__init__: id=%s, api_key=***, retry_count=%d, ' 'monitor_regions=%s, parallelism=%s, client_config=%s', id, retry_count, monitor_regions, parallelism, @@ -480,8 +480,7 @@ class Ns1Provider(BaseProvider): return filter_chain def _encode_notes(self, data): - return ' '.join(['{}:{}'.format(k, v) - for k, v in sorted(data.items())]) + return ' '.join([f'{k}:{v}' for k, v in sorted(data.items())]) def _parse_notes(self, note): data = {} @@ -515,13 +514,13 @@ class Ns1Provider(BaseProvider): ca_province = meta.get('ca_province', []) for cntry in country: con = country_alpha2_to_continent_code(cntry) - key = '{}-{}'.format(con, cntry) + key = f'{con}-{cntry}' geo[key].extend(answer['answer']) for state in us_state: - key = 'NA-US-{}'.format(state) + key = f'NA-US-{state}' geo[key].extend(answer['answer']) for province in ca_province: - key = 'NA-CA-{}'.format(province) + key = f'NA-CA-{province}' geo[key].extend(answer['answer']) for code in meta.get('iso_region_code', []): key = code @@ -660,7 +659,7 @@ class Ns1Provider(BaseProvider): if con in self._CONTINENT_TO_LIST_OF_COUNTRIES: special_continents.setdefault(con, set()).add(country) else: - geos.add('{}-{}'.format(con, country)) + geos.add(f'{con}-{country}') for continent, countries in special_continents.items(): if countries == self._CONTINENT_TO_LIST_OF_COUNTRIES[ @@ -670,15 +669,15 @@ class Ns1Provider(BaseProvider): else: # Partial countries found, so just add them as-is to geos for c in countries: - geos.add('{}-{}'.format(continent, c)) + geos.add(f'{continent}-{c}') # States and provinces are easy too, # just assume NA-US or NA-CA for state in meta.get('us_state', []): - geos.add('NA-US-{}'.format(state)) + geos.add(f'NA-US-{state}') for province in meta.get('ca_province', []): - geos.add('NA-CA-{}'.format(province)) + geos.add(f'NA-CA-{province}') if geos: # There are geos, combine them with any existing geos for this @@ -892,7 +891,7 @@ class Ns1Provider(BaseProvider): _type = record['type'] if _type not in self.SUPPORTS: continue - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') name = zone.hostname_from_fqdn(record['domain']) data = data_for(_type, record) record = Record.new(zone, name, data, source=self, lenient=lenient) @@ -969,7 +968,7 @@ class Ns1Provider(BaseProvider): def _feed_create(self, monitor): monitor_id = monitor['id'] self.log.debug('_feed_create: monitor=%s', monitor_id) - name = '{} - {}'.format(monitor['name'], self._uuid()[:6]) + name = f'{monitor["name"]} - {self._uuid()[:6]}' # Create the data feed config = { @@ -1037,7 +1036,7 @@ class Ns1Provider(BaseProvider): }, 'frequency': 60, 'job_type': 'tcp', - 'name': '{} - {} - {}'.format(host, _type, value), + 'name': f'{host} - {_type} - {value}', 'notes': self._encode_notes({ 'host': host, 'type': _type, @@ -1055,8 +1054,8 @@ class Ns1Provider(BaseProvider): # IF it's HTTP we need to send the request string path = record.healthcheck_path host = record.healthcheck_host(value=value) - request = r'GET {path} HTTP/1.0\r\nHost: {host}\r\n' \ - r'User-agent: NS1\r\n\r\n'.format(path=path, host=host) + request = fr'GET {path} HTTP/1.0\r\nHost: {host}\r\n' \ + r'User-agent: NS1\r\n\r\n' ret['config']['send'] = request # We'll also expect a HTTP response ret['rules'] = [{ @@ -1238,7 +1237,7 @@ class Ns1Provider(BaseProvider): if georegion: georegion_meta = dict(meta) georegion_meta['georegion'] = sorted(georegion) - regions['{}__georegion'.format(pool_name)] = { + regions[f'{pool_name}__georegion'] = { 'meta': georegion_meta, } @@ -1255,12 +1254,12 @@ class Ns1Provider(BaseProvider): country_state_meta['us_state'] = sorted(us_state) if ca_province: country_state_meta['ca_province'] = sorted(ca_province) - regions['{}__country'.format(pool_name)] = { + regions[f'{pool_name}__country'] = { 'meta': country_state_meta, } elif not georegion: # If there's no targeting it's a catchall - regions['{}__catchall'.format(pool_name)] = { + regions[f'{pool_name}__catchall'] = { 'meta': meta, } @@ -1403,7 +1402,7 @@ class Ns1Provider(BaseProvider): ns1_record['domain'], ns1_record['type']) if 'filters' in full_rec: - filter_key = '{}.'.format(ns1_record['domain']) + filter_key = f'{ns1_record["domain"]}.' ns1_filters[filter_key] = full_rec['filters'] return ns1_filters @@ -1412,8 +1411,7 @@ class Ns1Provider(BaseProvider): disabled_count = ['disabled' in f for f in filters].count(True) if disabled_count and disabled_count != len(filters): # Some filters have the disabled flag, and some don't. Disallow - exception_msg = 'Mixed disabled flag in filters for {}'.format( - domain) + exception_msg = f'Mixed disabled flag in filters for {domain}' raise Ns1Exception(exception_msg) return disabled_count == len(filters) @@ -1431,7 +1429,7 @@ class Ns1Provider(BaseProvider): # Check if filters for existing domains need an update # Needs an explicit check since there might be no change in the # config at all. Filters however might still need an update - domain = '{}.{}'.format(record.name, record.zone.name) + domain = f'{record.name}.{record.zone.name}' if domain in ns1_filters: domain_filters = ns1_filters[domain] if not self._disabled_flag_in_filters(domain_filters, domain): @@ -1463,8 +1461,7 @@ class Ns1Provider(BaseProvider): zone = new.zone.name[:-1] domain = new.fqdn[:-1] _type = new._type - params, active_monitor_ids = \ - getattr(self, '_params_for_{}'.format(_type))(new) + params, active_monitor_ids = getattr(self, f'_params_for_{_type}')(new) self._client.records_create(zone, domain, _type, **params) self._monitors_gc(new, active_monitor_ids) @@ -1473,8 +1470,7 @@ class Ns1Provider(BaseProvider): zone = new.zone.name[:-1] domain = new.fqdn[:-1] _type = new._type - params, active_monitor_ids = \ - getattr(self, '_params_for_{}'.format(_type))(new) + params, active_monitor_ids = getattr(self, f'_params_for_{_type}')(new) self._client.records_update(zone, domain, _type, **params) # If we're cleaning up we need to send in the old record since it'd # have anything that needs cleaning up @@ -1518,5 +1514,4 @@ class Ns1Provider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(ns1_zone, - change) + getattr(self, f'_apply_{class_name}')(ns1_zone, change) From e1cdfbdc8864cbdbc09217516a9236fcb6cb83f3 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:07:29 -0700 Subject: [PATCH 22/34] f-strings for OvhProvider --- octodns/provider/ovh.py | 50 +++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/octodns/provider/ovh.py b/octodns/provider/ovh.py index 9f7cd9a..6ff738a 100644 --- a/octodns/provider/ovh.py +++ b/octodns/provider/ovh.py @@ -45,7 +45,7 @@ class OvhProvider(BaseProvider): def __init__(self, id, endpoint, application_key, application_secret, consumer_key, *args, **kwargs): - self.log = logging.getLogger('OvhProvider[{}]'.format(id)) + self.log = logging.getLogger(f'OvhProvider[{id}]') self.log.debug('__init__: id=%s, endpoint=%s, application_key=%s, ' 'application_secret=***, consumer_key=%s', id, endpoint, application_key, consumer_key) @@ -81,7 +81,7 @@ class OvhProvider(BaseProvider): self.log.warning('Not managed record of type %s, skip', _type) continue - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record = Record.new(zone, name, data_for(_type, records), source=self, lenient=lenient) zone.add_record(record, lenient=lenient) @@ -98,15 +98,14 @@ class OvhProvider(BaseProvider): len(changes)) for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name).lower())(zone_name, - change) + getattr(self, f'_apply_{class_name}'.lower())(zone_name, change) # We need to refresh the zone to really apply the changes - self._client.post('/domain/zone/{}/refresh'.format(zone_name)) + self._client.post(f'/domain/zone/{zone_name}/refresh') def _apply_create(self, zone_name, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self.create_record(zone_name, params) @@ -198,7 +197,7 @@ class OvhProvider(BaseProvider): values.append({ 'port': port, 'priority': priority, - 'target': '{}.'.format(target), + 'target': f'{target}.', 'weight': weight }) return { @@ -264,8 +263,7 @@ class OvhProvider(BaseProvider): def _params_for_CAA(record): for value in record.values: yield { - 'target': '{} {} "{}"'.format(value.flags, value.tag, - value.value), + 'target': f'{value.flags} {value.tag} "{value.value}"', 'subDomain': record.name, 'ttl': record.ttl, 'fieldType': record._type @@ -275,7 +273,7 @@ class OvhProvider(BaseProvider): def _params_for_MX(record): for value in record.values: yield { - 'target': '%d %s' % (value.preference, value.exchange), + 'target': f'{value.preference:d} {value.exchange}', 'subDomain': record.name, 'ttl': record.ttl, 'fieldType': record._type @@ -284,9 +282,8 @@ class OvhProvider(BaseProvider): @staticmethod def _params_for_NAPTR(record): for value in record.values: - content = '{} {} "{}" "{}" "{}" {}' \ - .format(value.order, value.preference, value.flags, - value.service, value.regexp, value.replacement) + content = f'{value.order} {value.preference} "{value.flags}" ' \ + f'"{value.service}" "{value.regexp}" {value.replacement}' yield { 'target': content, 'subDomain': record.name, @@ -298,10 +295,8 @@ class OvhProvider(BaseProvider): def _params_for_SRV(record): for value in record.values: yield { - 'target': '{} {} {} {}'.format(value.priority, - value.weight, - value.port, - value.target), + 'target': f'{value.priority} {value.weight} {value.port} ' + f'{value.target}', 'subDomain': record.name, 'ttl': record.ttl, 'fieldType': record._type @@ -311,9 +306,8 @@ class OvhProvider(BaseProvider): def _params_for_SSHFP(record): for value in record.values: yield { - 'target': '{} {} {}'.format(value.algorithm, - value.fingerprint_type, - value.fingerprint), + 'target': f'{value.algorithm} {value.fingerprint_type} ' + f'{value.fingerprint}', 'subDomain': record.name, 'ttl': record.ttl, 'fieldType': record._type @@ -386,7 +380,7 @@ class OvhProvider(BaseProvider): :param zone_name: Name of zone :return: list of id's records """ - records = self._client.get('/domain/zone/{}/record'.format(zone_name)) + records = self._client.get(f'/domain/zone/{zone_name}/record') return [self.get_record(zone_name, record_id) for record_id in records] def get_record(self, zone_name, record_id): @@ -396,8 +390,7 @@ class OvhProvider(BaseProvider): :param record_id: Id of the record :return: Value of the record """ - return self._client.get( - '/domain/zone/{}/record/{}'.format(zone_name, record_id)) + return self._client.get(f'/domain/zone/{zone_name}/record/{record_id}') def delete_records(self, zone_name, record_type, subdomain): """ @@ -406,7 +399,7 @@ class OvhProvider(BaseProvider): :param record_type: fieldType :param subdomain: subDomain """ - records = self._client.get('/domain/zone/{}/record'.format(zone_name), + records = self._client.get(f'/domain/zone/{zone_name}/record', fieldType=record_type, subDomain=subdomain) for record in records: self.delete_record(zone_name, record) @@ -417,10 +410,8 @@ class OvhProvider(BaseProvider): :param zone_name: Name of the zone :param record_id: Id of the record """ - self.log.debug('Delete record: zone: %s, id %s', zone_name, - record_id) - self._client.delete( - '/domain/zone/{}/record/{}'.format(zone_name, record_id)) + self.log.debug('Delete record: zone: %s, id %s', zone_name, record_id) + self._client.delete(f'/domain/zone/{zone_name}/record/{record_id}') def create_record(self, zone_name, params): """ @@ -431,5 +422,4 @@ class OvhProvider(BaseProvider): """ self.log.debug('Create record: zone: %s, id %s', zone_name, params) - return self._client.post('/domain/zone/{}/record'.format(zone_name), - **params) + return self._client.post(f'/domain/zone/{zone_name}/record', **params) From 7f6b08b4608ba1a7a317eb572a9a403ae936d1c1 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:09:09 -0700 Subject: [PATCH 23/34] f-strings for PwerDnsProvider --- octodns/provider/powerdns.py | 43 +++++++++++++++--------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/octodns/provider/powerdns.py b/octodns/provider/powerdns.py index 0e4a5d9..900e879 100644 --- a/octodns/provider/powerdns.py +++ b/octodns/provider/powerdns.py @@ -38,8 +38,8 @@ class PowerDnsBaseProvider(BaseProvider): def _request(self, method, path, data=None): self.log.debug('_request: method=%s, path=%s', method, path) - url = '{}://{}:{}/api/v1/servers/localhost/{}' \ - .format(self.scheme, self.host, self.port, path).rstrip("/") + url = f'{self.scheme}://{self.host}:{self.port}/api/v1/servers/' \ + f'localhost/{path}'.rstrip('/') # Strip trailing / from url. resp = self._sess.request(method, url, json=data, timeout=self.timeout) self.log.debug('_request: status=%d', resp.status_code) @@ -204,8 +204,7 @@ class PowerDnsBaseProvider(BaseProvider): except HTTPError as e: if e.response.status_code == 401: # Nicer error message for auth problems - raise Exception('PowerDNS unauthorized host={}' - .format(self.host)) + raise Exception(f'PowerDNS unauthorized host={self.host}') raise version = resp.json()['version'] @@ -241,14 +240,13 @@ class PowerDnsBaseProvider(BaseProvider): resp = None try: - resp = self._get('zones/{}'.format(zone.name)) + resp = self._get(f'zones/{zone.name}') self.log.debug('populate: loaded') except HTTPError as e: error = self._get_error(e) if e.response.status_code == 401: # Nicer error message for auth problems - raise Exception('PowerDNS unauthorized host={}' - .format(self.host)) + raise Exception(f'PowerDNS unauthorized host={self.host}') elif e.response.status_code == 404 \ and self.check_status_not_found: # 404 means powerdns doesn't know anything about the requested @@ -275,7 +273,7 @@ class PowerDnsBaseProvider(BaseProvider): _type = rrset['type'] if _type == 'SOA': continue - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') record_name = zone.hostname_from_fqdn(rrset['name']) record = Record.new(zone, record_name, data_for(rrset), source=self, lenient=lenient) @@ -295,7 +293,7 @@ class PowerDnsBaseProvider(BaseProvider): def _records_for_CAA(self, record): return [{ - 'content': '{} {} "{}"'.format(v.flags, v.tag, v.value), + 'content': f'{v.flags} {v.tag} "{v.value}"', 'disabled': False } for v in record.values] @@ -307,7 +305,7 @@ class PowerDnsBaseProvider(BaseProvider): _records_for_PTR = _records_for_single def _records_for_quoted(self, record): - return [{'content': '"{}"'.format(v), 'disabled': False} + return [{'content': f'"{v}"', 'disabled': False} for v in record.values] _records_for_SPF = _records_for_quoted @@ -336,36 +334,32 @@ class PowerDnsBaseProvider(BaseProvider): def _records_for_MX(self, record): return [{ - 'content': '{} {}'.format(v.preference, v.exchange), + 'content': f'{v.preference} {v.exchange}', 'disabled': False } for v in record.values] def _records_for_NAPTR(self, record): return [{ - 'content': '{} {} "{}" "{}" "{}" {}'.format(v.order, v.preference, - v.flags, v.service, - v.regexp, - v.replacement), + 'content': f'{v.order} {v.preference} "{v.flags}" "{v.service}" ' + f'"{v.regexp}" {v.replacement}', 'disabled': False } for v in record.values] def _records_for_SSHFP(self, record): return [{ - 'content': '{} {} {}'.format(v.algorithm, v.fingerprint_type, - v.fingerprint), + 'content': f'{v.algorithm} {v.fingerprint_type} {v.fingerprint}', 'disabled': False } for v in record.values] def _records_for_SRV(self, record): return [{ - 'content': '{} {} {} {}'.format(v.priority, v.weight, v.port, - v.target), + 'content': f'{v.priority} {v.weight} {v.port} {v.target}', 'disabled': False } for v in record.values] def _mod_Create(self, change): new = change.new - records_for = getattr(self, '_records_for_{}'.format(new._type)) + records_for = getattr(self, f'_records_for_{new._type}') return { 'name': new.fqdn, 'type': new._type, @@ -378,7 +372,7 @@ class PowerDnsBaseProvider(BaseProvider): def _mod_Delete(self, change): existing = change.existing - records_for = getattr(self, '_records_for_{}'.format(existing._type)) + records_for = getattr(self, f'_records_for_{existing._type}') return { 'name': existing.fqdn, 'type': existing._type, @@ -429,7 +423,7 @@ class PowerDnsBaseProvider(BaseProvider): mods = [] for change in changes: class_name = change.__class__.__name__ - mods.append(getattr(self, '_mod_{}'.format(class_name))(change)) + mods.append(getattr(self, f'_mod_{class_name}')(change)) # Ensure that any DELETE modifications always occur before any REPLACE # modifications. This ensures that an A record can be replaced by a @@ -439,8 +433,7 @@ class PowerDnsBaseProvider(BaseProvider): self.log.debug('_apply: sending change request') try: - self._patch('zones/{}'.format(desired.name), - data={'rrsets': mods}) + self._patch(f'zones/{desired.name}', data={'rrsets': mods}) self.log.debug('_apply: patched') except HTTPError as e: error = self._get_error(e) @@ -510,7 +503,7 @@ class PowerDnsProvider(PowerDnsBaseProvider): def __init__(self, id, host, api_key, port=8081, nameserver_values=None, nameserver_ttl=600, *args, **kwargs): - self.log = logging.getLogger('PowerDnsProvider[{}]'.format(id)) + self.log = logging.getLogger(f'PowerDnsProvider[{id}]') self.log.debug('__init__: id=%s, host=%s, port=%d, ' 'nameserver_values=%s, nameserver_ttl=%d', id, host, port, nameserver_values, nameserver_ttl) From 0e458e0f6e95d4ccf877ec3cc7b6c636bdc04643 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:09:50 -0700 Subject: [PATCH 24/34] f-strings for RackspaceProvider --- octodns/provider/rackspace.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/octodns/provider/rackspace.py b/octodns/provider/rackspace.py index 7fed05b..db3696c 100644 --- a/octodns/provider/rackspace.py +++ b/octodns/provider/rackspace.py @@ -58,7 +58,7 @@ class RackspaceProvider(BaseProvider): # The api key that grants access for that user (required) api_key: api-key ''' - self.log = logging.getLogger('RackspaceProvider[{}]'.format(id)) + self.log = logging.getLogger(f'RackspaceProvider[{id}]') super(RackspaceProvider, self).__init__(id, *args, **kwargs) auth_token, dns_endpoint = self._get_auth_token(username, api_key) @@ -91,7 +91,7 @@ class RackspaceProvider(BaseProvider): def _request(self, method, path, data=None, pagination_key=None): self.log.debug('_request: method=%s, path=%s', method, path) - url = '{}/{}'.format(self.dns_endpoint, path) + url = f'{self.dns_endpoint}/{path}' if pagination_key: resp = self._paginated_request_for_url(method, url, data, @@ -194,8 +194,7 @@ class RackspaceProvider(BaseProvider): resp_data = None try: domain_id = self._get_zone_id_for(zone) - resp_data = self._request('GET', - 'domains/{}/records'.format(domain_id), + resp_data = self._request('GET', f'domains/{domain_id}/records', pagination_key='records') self.log.debug('populate: loaded') except HTTPError as e: @@ -213,8 +212,7 @@ class RackspaceProvider(BaseProvider): records = self._group_records(resp_data) for record_type, records_of_type in records.items(): for raw_record_name, record_set in records_of_type.items(): - data_for = getattr(self, - '_data_for_{}'.format(record_type)) + data_for = getattr(self, f'_data_for_{record_type}') record_name = zone.hostname_from_fqdn(raw_record_name) record = Record.new(zone, record_name, data_for(record_set), @@ -291,7 +289,7 @@ class RackspaceProvider(BaseProvider): self._get_values(change.new)) def _create_given_change_values(self, change, values): - transformer = getattr(self, "_record_for_{}".format(change.new._type)) + transformer = getattr(self, f"_record_for_{change.new._type}") return [transformer(change.new, v) for v in values] def _mod_Update(self, change): @@ -311,8 +309,7 @@ class RackspaceProvider(BaseProvider): update_out = [] update_values = set(new_values).intersection(set(existing_values)) for value in update_values: - transformer = getattr(self, - "_record_for_{}".format(change.new._type)) + transformer = getattr(self, f"_record_for_{change.new._type}") prior_rs_record = transformer(change.existing, value) prior_key = self._key_for_record(prior_rs_record) next_rs_record = transformer(change.new, value) @@ -329,8 +326,7 @@ class RackspaceProvider(BaseProvider): change.existing)) def _delete_given_change_values(self, change, values): - transformer = getattr(self, "_record_for_{}".format( - change.existing._type)) + transformer = getattr(self, f"_record_for_{change.existing._type}") out = [] for value in values: rs_record = transformer(change.existing, value) @@ -367,12 +363,12 @@ class RackspaceProvider(BaseProvider): if deletes: params = "&".join(sorted(deletes)) - self._delete('domains/{}/records?{}'.format(domain_id, params)) + self._delete(f'domains/{domain_id}/records?{params}') if updates: data = {"records": sorted(updates, key=_value_keyer)} - self._put('domains/{}/records'.format(domain_id), data=data) + self._put(f'domains/{domain_id}/records', data=data) if creates: data = {"records": sorted(creates, key=_value_keyer)} - self._post('domains/{}/records'.format(domain_id), data=data) + self._post(f'domains/{domain_id}/records', data=data) From 58b2dc1696fd63089a6581655b560a1efbed5a98 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:13:30 -0700 Subject: [PATCH 25/34] f-strings for Route53Provider --- octodns/provider/route53.py | 145 ++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 80 deletions(-) diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index 0ef60bc..0ecce72 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -47,7 +47,7 @@ class _Route53Record(EqualityTupleMixin): # healthchecks, which hopefully never happens. fqdn = record.fqdn ret.add(_Route53Record(provider, record, creating, - '_octodns-default-pool.{}'.format(fqdn))) + f'_octodns-default-pool.{fqdn}')) # Pools for pool_name, pool in record.dynamic.pools.items(): @@ -136,7 +136,7 @@ class _Route53Record(EqualityTupleMixin): self._type = record._type self.ttl = record.ttl - values_for = getattr(self, '_values_for_{}'.format(self._type)) + values_for = getattr(self, f'_values_for_{self._type}') self.values = values_for(record) def mod(self, action, existing_rrsets): @@ -156,7 +156,7 @@ class _Route53Record(EqualityTupleMixin): def __hash__(self): 'sub-classes should never use this method' - return '{}:{}'.format(self.fqdn, self._type).__hash__() + return f'{self.fqdn}:{self._type}'.__hash__() def _equality_tuple(self): '''Sub-classes should call up to this and return its value and add @@ -164,8 +164,8 @@ class _Route53Record(EqualityTupleMixin): return (self.__class__.__name__, self.fqdn, self._type) def __repr__(self): - return '_Route53Record<{} {} {} {}>'.format(self.fqdn, self._type, - self.ttl, self.values) + return '_Route53Record<{self.fqdn} {self._type} {self.ttl} ' \ + f'{self.values}>' def _value_convert_value(self, value, record): return value @@ -184,7 +184,7 @@ class _Route53Record(EqualityTupleMixin): _values_for_NS = _values_for_values def _value_convert_CAA(self, value, record): - return '{} {} "{}"'.format(value.flags, value.tag, value.value) + return f'{value.flags} {value.tag} "{value.value}"' def _values_for_CAA(self, record): return [self._value_convert_CAA(v, record) for v in record.values] @@ -196,18 +196,17 @@ class _Route53Record(EqualityTupleMixin): _values_for_PTR = _values_for_value def _value_convert_MX(self, value, record): - return '{} {}'.format(value.preference, value.exchange) + return f'{value.preference} {value.exchange}' def _values_for_MX(self, record): return [self._value_convert_MX(v, record) for v in record.values] def _value_convert_NAPTR(self, value, record): - return '{} {} "{}" "{}" "{}" {}' \ - .format(value.order, value.preference, - value.flags if value.flags else '', - value.service if value.service else '', - value.regexp if value.regexp else '', - value.replacement) + flags = value.flags if value.flags else '' + service = value.service if value.service else '' + regexp = value.regexp if value.regexp else '' + return f'{value.order} {value.preference} "{flags}" "{service}" ' \ + f'"{regexp}" {value.replacement}' def _values_for_NAPTR(self, record): return [self._value_convert_NAPTR(v, record) for v in record.values] @@ -225,8 +224,7 @@ class _Route53Record(EqualityTupleMixin): _values_for_TXT = _values_for_quoted def _value_for_SRV(self, value, record): - return '{} {} {} {}'.format(value.priority, value.weight, - value.port, value.target) + return f'{value.priority} {value.weight} {value.port} {value.target}' def _values_for_SRV(self, record): return [self._value_for_SRV(v, record) for v in record.values] @@ -236,7 +234,7 @@ class _Route53DynamicPool(_Route53Record): def __init__(self, provider, hosted_zone_id, record, pool_name, creating, target_name=None): - fqdn_override = '_octodns-{}-pool.{}'.format(pool_name, record.fqdn) + fqdn_override = f'_octodns-{pool_name}-pool.{record.fqdn}' super(_Route53DynamicPool, self) \ .__init__(provider, record, creating, fqdn_override=fqdn_override) @@ -246,12 +244,10 @@ class _Route53DynamicPool(_Route53Record): self.target_name = target_name if target_name: # We're pointing down the chain - self.target_dns_name = '_octodns-{}-pool.{}'.format(target_name, - record.fqdn) + self.target_dns_name = f'_octodns-{target_name}-pool.{record.fqdn}' else: # We're a paimary, point at our values - self.target_dns_name = '_octodns-{}-value.{}'.format(pool_name, - record.fqdn) + self.target_dns_name = f'_octodns-{pool_name}-value.{record.fqdn}' @property def mode(self): @@ -260,9 +256,8 @@ class _Route53DynamicPool(_Route53Record): @property def identifer(self): if self.target_name: - return '{}-{}-{}'.format(self.pool_name, self.mode, - self.target_name) - return '{}-{}'.format(self.pool_name, self.mode) + return f'{self.pool_name}-{self.mode}-{self.target_name}' + return f'{self.pool_name}-{self.mode}' def mod(self, action, existing_rrsets): return { @@ -281,12 +276,11 @@ class _Route53DynamicPool(_Route53Record): } def __hash__(self): - return '{}:{}:{}'.format(self.fqdn, self._type, - self.identifer).__hash__() + return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__() def __repr__(self): - return '_Route53DynamicPool<{} {} {} {}>' \ - .format(self.fqdn, self._type, self.mode, self.target_dns_name) + return f'_Route53DynamicPool<{self.fqdn} {self._type} {self.mode} ' \ + f'{self.target_dns_name}>' class _Route53DynamicRule(_Route53Record): @@ -300,12 +294,11 @@ class _Route53DynamicRule(_Route53Record): self.pool_name = pool_name self.index = index - self.target_dns_name = '_octodns-{}-pool.{}'.format(pool_name, - record.fqdn) + self.target_dns_name = f'_octodns-{pool_name}-pool.{record.fqdn}' @property def identifer(self): - return '{}-{}-{}'.format(self.index, self.pool_name, self.geo) + return f'{self.index}-{self.pool_name}-{self.geo}' def mod(self, action, existing_rrsets): rrset = { @@ -345,26 +338,24 @@ class _Route53DynamicRule(_Route53Record): } def __hash__(self): - return '{}:{}:{}'.format(self.fqdn, self._type, - self.identifer).__hash__() + return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__() def __repr__(self): - return '_Route53DynamicRule<{} {} {} {} {}>' \ - .format(self.fqdn, self._type, self.index, self.geo, - self.target_dns_name) + return f'_Route53DynamicRule<{self.fqdn} {self._type} {self.index} ' \ + f'{self.geo} {self.target_dns_name}>' class _Route53DynamicValue(_Route53Record): def __init__(self, provider, record, pool_name, value, weight, index, creating): - fqdn_override = '_octodns-{}-value.{}'.format(pool_name, record.fqdn) + fqdn_override = f'_octodns-{pool_name}-value.{record.fqdn}' super(_Route53DynamicValue, self).__init__(provider, record, creating, fqdn_override=fqdn_override) self.pool_name = pool_name self.index = index - value_convert = getattr(self, '_value_convert_{}'.format(record._type)) + value_convert = getattr(self, f'_value_convert_{record._type}') self.value = value_convert(value, record) self.weight = weight @@ -373,7 +364,7 @@ class _Route53DynamicValue(_Route53Record): @property def identifer(self): - return '{}-{:03d}'.format(self.pool_name, self.index) + return f'{self.pool_name}-{self.index:03d}' def mod(self, action, existing_rrsets): @@ -404,12 +395,11 @@ class _Route53DynamicValue(_Route53Record): } def __hash__(self): - return '{}:{}:{}'.format(self.fqdn, self._type, - self.identifer).__hash__() + return f'{self.fqdn}:{self._type}:{self.identifer}'.__hash__() def __repr__(self): - return '_Route53DynamicValue<{} {} {} {}>' \ - .format(self.fqdn, self._type, self.identifer, self.value) + return f'_Route53DynamicValue<{self.fqdn} {self._type} ' \ + f'{self.identifer} {self.value}>' class _Route53GeoDefault(_Route53Record): @@ -430,11 +420,11 @@ class _Route53GeoDefault(_Route53Record): } def __hash__(self): - return '{}:{}:default'.format(self.fqdn, self._type).__hash__() + return f'{self.fqdn}:{self._type}:default'.__hash__() def __repr__(self): - return '_Route53GeoDefault<{} {} {} {}>'.format(self.fqdn, self._type, - self.ttl, self.values) + return f'_Route53GeoDefault<{self.fqdn} {self._type} {self.ttl} ' \ + f'{self.values}>' class _Route53GeoRecord(_Route53Record): @@ -499,18 +489,15 @@ class _Route53GeoRecord(_Route53Record): } def __hash__(self): - return '{}:{}:{}'.format(self.fqdn, self._type, - self.geo.code).__hash__() + return f'{self.fqdn}:{self._type}:{self.geo.code}'.__hash__() def _equality_tuple(self): return super(_Route53GeoRecord, self)._equality_tuple() + \ (self.geo.code,) def __repr__(self): - return '_Route53GeoRecord<{} {} {} {} {}>'.format(self.fqdn, - self._type, self.ttl, - self.geo.code, - self.values) + return f'_Route53GeoRecord<{self.fqdn} {self._type} {self.ttl} ' \ + f'{self.geo.code} {self.values}>' class Route53ProviderException(ProviderException): @@ -552,7 +539,7 @@ def _mod_keyer(mod): unique_id = rrset['SetIdentifier'] else: if 'SetIdentifier' in rrset: - unique_id = '{}-{}'.format(rrset['Name'], rrset['SetIdentifier']) + unique_id = f'{rrset["Name"]}-{rrset["SetIdentifier"]}' else: unique_id = rrset['Name'] @@ -626,13 +613,13 @@ class Route53Provider(BaseProvider): session_token=None, delegation_set_id=None, *args, **kwargs): self.max_changes = max_changes self.delegation_set_id = delegation_set_id - _msg = 'access_key_id={}, secret_access_key=***, ' \ - 'session_token=***'.format(access_key_id) + _msg = f'access_key_id={access_key_id}, secret_access_key=***, ' \ + 'session_token=***' use_fallback_auth = access_key_id is None and \ secret_access_key is None and session_token is None if use_fallback_auth: _msg = 'auth=fallback' - self.log = logging.getLogger('Route53Provider[{}]'.format(id)) + self.log = logging.getLogger(f'Route53Provider[{id}]') self.log.debug('__init__: id=%s, %s', id, _msg) super(Route53Provider, self).__init__(id, *args, **kwargs) @@ -710,9 +697,9 @@ class Route53Provider(BaseProvider): return cn = country_alpha2_to_continent_code(cc) try: - return '{}-{}-{}'.format(cn, cc, loc['SubdivisionCode']) + return f'{cn}-{cc}-{loc["SubdivisionCode"]}' except KeyError: - return '{}-{}'.format(cn, cc) + return f'{cn}-{cc}' def _data_for_geo(self, rrset): ret = { @@ -876,7 +863,7 @@ class Route53Provider(BaseProvider): if pool_name == 'default': # default becomes the base for the record and its # value(s) will fill the non-dynamic values - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data.update(data_for(rrset)) elif rrset['Failover'] == 'SECONDARY': # This is a failover record, we'll ignore PRIMARY, but @@ -940,17 +927,16 @@ class Route53Provider(BaseProvider): if not g.startswith('NA-CA-')] if not filtered_geos: # We've removed all geos, we'll have to skip this rule - msg = 'NA-CA-* not supported for {}' \ - .format(record.fqdn) - fallback = 'skipping rule {}'.format(i) + msg = f'NA-CA-* not supported for {record.fqdn}' + fallback = f'skipping rule {i}' self.supports_warn_or_except(msg, fallback) continue elif geos != filtered_geos: - msg = 'NA-CA-* not supported for {}' \ - .format(record.fqdn) - fallback = 'filtering rule {} from ({}) to ({})' \ - .format(i, ', '.join(geos), - ', '.join(filtered_geos)) + msg = f'NA-CA-* not supported for {record.fqdn}' + before = ', '.join(geos) + after = ', '.join(filtered_geos) + fallback = f'filtering rule {i} from ({before}) to ' \ + f'({after})' self.supports_warn_or_except(msg, fallback) rule.data['geos'] = filtered_geos rules.append(rule) @@ -1001,7 +987,7 @@ class Route53Provider(BaseProvider): % rrset['Name']) continue # A basic record (potentially including geo) - data = getattr(self, '_data_for_{}'.format(record_type))(rrset) + data = getattr(self, f'_data_for_{record_type}')(rrset) records[record_name][record_type].append(data) # Convert the dynamic rrsets to Records @@ -1137,8 +1123,8 @@ class Route53Provider(BaseProvider): # we're looking for a healthcheck with the current version & our record # type, we'll ignore anything else - expected_ref = '{}:{}:{}:'.format(self.HEALTH_CHECK_VERSION, - record._type, record.fqdn) + expected_ref = \ + f'{self.HEALTH_CHECK_VERSION}:{record._type}:{record.fqdn}:' for id, health_check in self.health_checks.items(): if not health_check['CallerReference'].startswith(expected_ref): # not match, ignore @@ -1175,16 +1161,16 @@ class Route53Provider(BaseProvider): if value: config['IPAddress'] = value - ref = '{}:{}:{}:{}'.format(self.HEALTH_CHECK_VERSION, record._type, - record.fqdn, uuid4().hex[:12]) + ref = f'{self.HEALTH_CHECK_VERSION}:{record._type}:{record.fqdn}:' + \ + uuid4().hex[:12] resp = self._conn.create_health_check(CallerReference=ref, HealthCheckConfig=config) health_check = resp['HealthCheck'] id = health_check['Id'] # Set a Name for the benefit of the UI - name = '{}:{} - {}'.format(record.fqdn, record._type, - value or healthcheck_host) + value_or_host = value or healthcheck_host + name = f'{record.fqdn}:{record._type} - {value_or_host}' self._conn.change_tags_for_resource(ResourceType='healthcheck', ResourceId=id, AddTags=[{ @@ -1221,12 +1207,11 @@ class Route53Provider(BaseProvider): # Now we need to run through ALL the health checks looking for those # that apply to this record, deleting any that do and are no longer in # use - expected_re = re.compile(r'^\d\d\d\d:{}:{}:' - .format(record._type, record.fqdn)) + expected_re = re.compile(fr'^\d\d\d\d:{record._type}:{record.fqdn}:') # UNITL 1.0: we'll clean out the previous version of Route53 health # checks as best as we can. expected_legacy_host = record.fqdn[:-1] - expected_legacy = '0000:{}:'.format(record._type) + expected_legacy = f'0000:{record._type}:' for id, health_check in self.health_checks.items(): ref = health_check['CallerReference'] if expected_re.match(ref) and id not in in_use: @@ -1423,7 +1408,8 @@ class Route53Provider(BaseProvider): existing_rrsets = self._load_records(zone_id) for c in changes: # Generate the mods for this change - mod_type = getattr(self, '_mod_{}'.format(c.__class__.__name__)) + klass = c.__class__.__name__ + mod_type = getattr(self, f'_mod_{klass}') mods = mod_type(c, zone_id, existing_rrsets) # Order our mods to make sure targets exist before alises point to @@ -1437,8 +1423,7 @@ class Route53Provider(BaseProvider): if mods_rs_count > self.max_changes: # a single mod resulted in too many ResourceRecords changes - raise Exception('Too many modifications: {}' - .format(mods_rs_count)) + raise Exception(f'Too many modifications: {mods_rs_count}') # r53 limits changesets to 1000 entries if (batch_rs_count + mods_rs_count) < self.max_changes: @@ -1469,7 +1454,7 @@ class Route53Provider(BaseProvider): batch.sort(key=_mod_keyer) uuid = uuid4().hex batch = { - 'Comment': 'Change: {}'.format(uuid), + 'Comment': f'Change: {uuid}', 'Changes': batch, } self.log.debug('_really_apply: sending change request, comment=%s', From 059bb5dbbc5a9a606dad4dea65aafe96df3a4c2f Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:14:28 -0700 Subject: [PATCH 26/34] f-strings for SelectelProvider --- octodns/provider/selectel.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/octodns/provider/selectel.py b/octodns/provider/selectel.py index 87f8d4f..5851253 100644 --- a/octodns/provider/selectel.py +++ b/octodns/provider/selectel.py @@ -39,7 +39,7 @@ class SelectelProvider(BaseProvider): API_URL = 'https://api.selectel.ru/domains/v1' def __init__(self, id, token, *args, **kwargs): - self.log = getLogger('SelectelProvider[{}]'.format(id)) + self.log = getLogger(f'SelectelProvider[{id}]') self.log.debug('__init__: id=%s', id) super(SelectelProvider, self).__init__(id, *args, **kwargs) @@ -55,7 +55,7 @@ class SelectelProvider(BaseProvider): def _request(self, method, path, params=None, data=None): self.log.debug('_request: method=%s, path=%s', method, path) - url = '{}{}'.format(self.API_URL, path) + url = f'{self.API_URL}{path}' resp = self._sess.request(method, url, params=params, json=data) self.log.debug('_request: status=%s', resp.status_code) @@ -69,7 +69,7 @@ class SelectelProvider(BaseProvider): return resp.json() def _get_total_count(self, path): - url = '{}{}'.format(self.API_URL, path) + url = f'{self.API_URL}{path}' resp = self._sess.request('HEAD', url) return int(resp.headers['X-Total-Count']) @@ -101,12 +101,11 @@ class SelectelProvider(BaseProvider): zone_name = desired.name[:-1] for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name).lower())(zone_name, - change) + getattr(self, f'_apply_{class_name}'.lower())(zone_name, change) def _apply_create(self, zone_name, change): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') for params in params_for(new): self.create_record(zone_name, params) @@ -178,7 +177,7 @@ class SelectelProvider(BaseProvider): return { 'ttl': records[0]['ttl'], 'type': _type, - 'values': ['{}.'.format(r['content']) for r in records], + 'values': [f'{r["content"]}.' for r in records], } def _data_for_MX(self, _type, records): @@ -186,7 +185,7 @@ class SelectelProvider(BaseProvider): for record in records: values.append({ 'preference': record['priority'], - 'exchange': '{}.'.format(record['content']), + 'exchange': f'{record["content"]}.', }) return { 'ttl': records[0]['ttl'], @@ -199,7 +198,7 @@ class SelectelProvider(BaseProvider): return { 'ttl': only['ttl'], 'type': _type, - 'value': '{}.'.format(only['content']) + 'value': f'{only["content"]}.', } def _data_for_TXT(self, _type, records): @@ -216,7 +215,7 @@ class SelectelProvider(BaseProvider): 'priority': record['priority'], 'weight': record['weight'], 'port': record['port'], - 'target': '{}.'.format(record['target']), + 'target': f'{record["target"]}.', }) return { @@ -239,7 +238,7 @@ class SelectelProvider(BaseProvider): values[name][record['type']].append(record) for name, types in values.items(): for _type, records in types.items(): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data = data_for(_type, records) record = Record.new(zone, name, data, source=self, lenient=lenient) @@ -260,7 +259,7 @@ class SelectelProvider(BaseProvider): return domains def zone_records(self, zone): - path = '/{}/records/'.format(zone.name[:-1]) + path = f'/{zone.name[:-1]}/records/' zone_records = [] total_count = self._get_total_count(path) @@ -288,24 +287,24 @@ class SelectelProvider(BaseProvider): else: domain_id = self.create_domain(zone_name)['id'] - path = '/{}/records/'.format(domain_id) + path = f'/{domain_id}/records/' return self._request('POST', path, data=data) def delete_record(self, domain, _type, zone): self.log.debug('Delete record. Domain: %s, Type: %s', domain, _type) domain_id = self._domain_list[domain]['id'] - records = self._zone_records.get('{}.'.format(domain), False) + records = self._zone_records.get(f'{domain}.', False) if not records: - path = '/{}/records/'.format(domain_id) + path = f'/{domain_id}/records/' records = self._request('GET', path) for record in records: full_domain = domain if zone: - full_domain = '{}{}'.format(zone, domain) + full_domain = f'{zone}{domain}' if record['type'] == _type and record['name'] == full_domain: - path = '/{}/records/{}'.format(domain_id, record['id']) + path = f'/{domain_id}/records/{record["id"]}' return self._request('DELETE', path) self.log.debug('Delete record failed (Record not found)') From f94690043371b1fec8430966ed1b89d2f520a21f Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:15:29 -0700 Subject: [PATCH 27/34] f-strings for UltraProvider --- octodns/provider/ultra.py | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/octodns/provider/ultra.py b/octodns/provider/ultra.py index e382a33..bb8403d 100644 --- a/octodns/provider/ultra.py +++ b/octodns/provider/ultra.py @@ -79,7 +79,7 @@ class UltraProvider(BaseProvider): data=None, json=None, json_response=True): self.log.debug('_request: method=%s, path=%s', method, path) - url = '{}{}'.format(self._base_uri, path) + url = f'{self._base_uri}{path}' resp = self._sess.request(method, url, params=params, @@ -128,12 +128,12 @@ class UltraProvider(BaseProvider): resp = self._post(path, data=data) self._sess.headers.update({ - 'Authorization': 'Bearer {}'.format(resp['access_token']), + 'Authorization': f'Bearer {resp["access_token"]}', }) def __init__(self, id, account, username, password, timeout=TIMEOUT, *args, **kwargs): - self.log = getLogger('UltraProvider[{}]'.format(id)) + self.log = getLogger(f'UltraProvider[{id}]') self.log.debug('__init__: id=%s, account=%s, username=%s, ' 'password=***', id, account, username) @@ -250,7 +250,7 @@ class UltraProvider(BaseProvider): return [] records = [] - path = '/v2/zones/{}/rrsets'.format(zone.name) + path = f'/v2/zones/{zone.name}/rrsets' offset = 0 limit = 100 paging = True @@ -269,7 +269,7 @@ class UltraProvider(BaseProvider): return self._zone_records[zone.name] def _record_for(self, zone, name, _type, records, lenient): - data_for = getattr(self, '_data_for_{}'.format(_type)) + data_for = getattr(self, f'_data_for_{_type}') data = data_for(_type, records) record = Record.new(zone, name, data, source=self, lenient=lenient) return record @@ -327,7 +327,7 @@ class UltraProvider(BaseProvider): for change in changes: class_name = change.__class__.__name__ - getattr(self, '_apply_{}'.format(class_name))(change) + getattr(self, f'_apply_{class_name}')(change) # Clear the cache self._zone_records.pop(name, None) @@ -380,25 +380,20 @@ class UltraProvider(BaseProvider): def _contents_for_SRV(self, record): return { 'ttl': record.ttl, - 'rdata': ['{} {} {} {}'.format(x.priority, - x.weight, - x.port, - x.target) for x in record.values] + 'rdata': [f'{x.priority} {x.weight} {x.port} {x.target}' + for x in record.values] } def _contents_for_CAA(self, record): return { 'ttl': record.ttl, - 'rdata': ['{} {} {}'.format(x.flags, - x.tag, - x.value) for x in record.values] + 'rdata': [f'{x.flags} {x.tag} {x.value}' for x in record.values] } def _contents_for_MX(self, record): return { 'ttl': record.ttl, - 'rdata': ['{} {}'.format(x.preference, - x.exchange) for x in record.values] + 'rdata': [f'{x.preference} {x.exchange}' for x in record.values] } def _gen_data(self, record): @@ -410,10 +405,8 @@ class UltraProvider(BaseProvider): else: record_type = record._type - path = '/v2/zones/{}/rrsets/{}/{}'.format(zone_name, - record_type, - record.fqdn) - contents_for = getattr(self, '_contents_for_{}'.format(record._type)) + path = f'/v2/zones/{zone_name}/rrsets/{record_type}/{record.fqdn}' + contents_for = getattr(self, f'_contents_for_{record._type}') return path, contents_for(record) def _apply_Create(self, change): @@ -459,7 +452,6 @@ class UltraProvider(BaseProvider): if existing_type == "ALIAS": existing_type = "APEXALIAS" - path = '/v2/zones/{}/rrsets/{}/{}'.format(zone_name, - existing_type, - existing.fqdn) + path = f'/v2/zones/{zone_name}/rrsets/{existing_type}/' + \ + existing.fqdn self._delete(path, json_response=False) From c36091062a8e90731b39b5e1950c6240994e73fa Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:41:30 -0700 Subject: [PATCH 28/34] f-strings for YamlProvider --- octodns/provider/yaml.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/octodns/provider/yaml.py b/octodns/provider/yaml.py index 803bbd4..aaf84c6 100644 --- a/octodns/provider/yaml.py +++ b/octodns/provider/yaml.py @@ -111,8 +111,8 @@ class YamlProvider(BaseProvider): def __init__(self, id, directory, default_ttl=3600, enforce_order=True, populate_should_replace=False, *args, **kwargs): - self.log = logging.getLogger('{}[{}]'.format( - self.__class__.__name__, id)) + klass = self.__class__.__name__ + self.log = logging.getLogger(f'{klass}[{id}]') self.log.debug('__init__: id=%s, directory=%s, default_ttl=%d, ' 'enforce_order=%d, populate_should_replace=%d', id, directory, default_ttl, enforce_order, @@ -150,7 +150,7 @@ class YamlProvider(BaseProvider): return False before = len(zone.records) - filename = join(self.directory, '{}yaml'.format(zone.name)) + filename = join(self.directory, f'{zone.name}yaml') self._populate_from_file(filename, zone, lenient) self.log.info('populate: found %s records, exists=False', @@ -188,7 +188,7 @@ class YamlProvider(BaseProvider): self._do_apply(desired, data) def _do_apply(self, desired, data): - filename = join(self.directory, '{}yaml'.format(desired.name)) + filename = join(self.directory, f'{desired.name}yaml') self.log.debug('_apply: writing filename=%s', filename) with open(filename, 'w') as fh: safe_dump(dict(data), fh) @@ -197,7 +197,7 @@ class YamlProvider(BaseProvider): def _list_all_yaml_files(directory): yaml_files = set() for f in listdir(directory): - filename = join(directory, '{}'.format(f)) + filename = join(directory, f) if f.endswith('.yaml') and isfile(filename): yaml_files.add(filename) return list(yaml_files) @@ -246,7 +246,7 @@ class SplitYamlProvider(YamlProvider): self.extension = extension def _zone_directory(self, zone): - filename = '{}{}'.format(zone.name[:-1], self.extension) + filename = f'{zone.name[:-1]}{self.extension}' return join(self.directory, filename) def populate(self, zone, target=False, lenient=False): @@ -278,7 +278,7 @@ class SplitYamlProvider(YamlProvider): if record in self.CATCHALL_RECORD_NAMES: catchall[record] = config continue - filename = join(zone_dir, '{}.yaml'.format(record)) + filename = join(zone_dir, f'{record}.yaml') self.log.debug('_apply: writing filename=%s', filename) with open(filename, 'w') as fh: record_data = {record: config} @@ -286,7 +286,7 @@ class SplitYamlProvider(YamlProvider): if catchall: # Scrub the trailing . to make filenames more sane. dname = desired.name[:-1] - filename = join(zone_dir, '${}.yaml'.format(dname)) + filename = join(zone_dir, f'${dname}.yaml') self.log.debug('_apply: writing catchall filename=%s', filename) with open(filename, 'w') as fh: safe_dump(catchall, fh) From fe66582edff144d2687cb56110bcd1a6c3e0c0d0 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 18:47:19 -0700 Subject: [PATCH 29/34] f-strings for Plan --- octodns/provider/plan.py | 41 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/octodns/provider/plan.py b/octodns/provider/plan.py index 69bd2b2..0a9c04f 100644 --- a/octodns/provider/plan.py +++ b/octodns/provider/plan.py @@ -12,7 +12,12 @@ from six import StringIO, text_type class UnsafePlan(Exception): - pass + + def __init__(self, why, update_pcent, update_threshold, change_count, + existing_count): + msg = f'{why}, {update_pcent:.2f} is over {update_threshold:.2f} %' \ + f'({change_count}/{existing_count})' + super(UnsafePlan, self).__init__(msg) class Plan(object): @@ -66,25 +71,23 @@ class Plan(object): delete_pcent = self.change_counts['Delete'] / existing_record_count if update_pcent > self.update_pcent_threshold: - raise UnsafePlan('Too many updates, {:.2f} is over {:.2f} %' - '({}/{})'.format( - update_pcent * 100, - self.update_pcent_threshold * 100, - self.change_counts['Update'], - existing_record_count)) + raise UnsafePlan('Too many updates', update_pcent * 100, + self.update_pcent_threshold * 100, + self.change_counts['Update'], + existing_record_count) if delete_pcent > self.delete_pcent_threshold: - raise UnsafePlan('Too many deletes, {:.2f} is over {:.2f} %' - '({}/{})'.format( - delete_pcent * 100, - self.delete_pcent_threshold * 100, - self.change_counts['Delete'], - existing_record_count)) + raise UnsafePlan('Too many deletes', delete_pcent * 100, + self.delete_pcent_threshold * 100, + self.change_counts['Delete'], + existing_record_count) def __repr__(self): - return 'Creates={}, Updates={}, Deletes={}, Existing Records={}' \ - .format(self.change_counts['Create'], self.change_counts['Update'], - self.change_counts['Delete'], - len(self.existing.records)) + creates = self.change_counts['Create'] + updates = self.change_counts['Update'] + deletes = self.change_counts['Delete'] + existing = len(self.existing.records) + return f'Creates={creates}, Updates={updates}, Deletes={deletes}, ' \ + f'Existing Records={existing}' class _PlanOutput(object): @@ -106,7 +109,7 @@ class PlanLogger(_PlanOutput): 'error': ERROR }[level.lower()] except (AttributeError, KeyError): - raise Exception('Unsupported level: {}'.format(level)) + raise Exception(f'Unsupported level: {level}') def run(self, log, plans, *args, **kwargs): hr = '*************************************************************' \ @@ -157,7 +160,7 @@ def _value_stringifier(record, sep): values = [record.value] for code, gv in sorted(getattr(record, 'geo', {}).items()): vs = ', '.join([text_type(v) for v in gv.values]) - values.append('{}: {}'.format(code, vs)) + values.append(f'{code}: {vs}') return sep.join(values) From adf08a178adb0759a44c18cb5deb3fd1ce1d90fc Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Sat, 4 Sep 2021 19:08:29 -0700 Subject: [PATCH 30/34] f-strings for Manager, Zone and yaml --- octodns/manager.py | 116 +++++++++++++++++++++------------------------ octodns/yaml.py | 4 +- octodns/zone.py | 29 +++++------- 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/octodns/manager.py b/octodns/manager.py index 104e445..7df65d9 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -111,16 +111,16 @@ class Manager(object): _class = provider_config.pop('class') except KeyError: self.log.exception('Invalid provider class') - raise ManagerException('Provider {} is missing class' - .format(provider_name)) + raise ManagerException(f'Provider {provider_name} is missing ' + 'class') _class = self._get_named_class('provider', _class) kwargs = self._build_kwargs(provider_config) try: self.providers[provider_name] = _class(provider_name, **kwargs) except TypeError: self.log.exception('Invalid provider config') - raise ManagerException('Incorrect provider config for {}' - .format(provider_name)) + raise ManagerException('Incorrect provider config for ' + + provider_name) self.processors = {} for processor_name, processor_config in \ @@ -129,8 +129,8 @@ class Manager(object): _class = processor_config.pop('class') except KeyError: self.log.exception('Invalid processor class') - raise ManagerException('Processor {} is missing class' - .format(processor_name)) + raise ManagerException(f'Processor {processor_name} is ' + 'missing class') _class = self._get_named_class('processor', _class) kwargs = self._build_kwargs(processor_config) try: @@ -138,8 +138,8 @@ class Manager(object): **kwargs) except TypeError: self.log.exception('Invalid processor config') - raise ManagerException('Incorrect processor config for {}' - .format(processor_name)) + raise ManagerException('Incorrect processor config for ' + + processor_name) zone_tree = {} # sort by reversed strings so that parent zones always come first @@ -173,8 +173,8 @@ class Manager(object): _class = plan_output_config.pop('class') except KeyError: self.log.exception('Invalid plan_output class') - raise ManagerException('plan_output {} is missing class' - .format(plan_output_name)) + raise ManagerException(f'plan_output {plan_output_name} is ' + 'missing class') _class = self._get_named_class('plan_output', _class) kwargs = self._build_kwargs(plan_output_config) try: @@ -182,8 +182,8 @@ class Manager(object): _class(plan_output_name, **kwargs) except TypeError: self.log.exception('Invalid plan_output config') - raise ManagerException('Incorrect plan_output config for {}' - .format(plan_output_name)) + raise ManagerException('Incorrect plan_output config for ' + + plan_output_name) def _get_named_class(self, _type, _class): try: @@ -192,15 +192,13 @@ class Manager(object): except (ImportError, ValueError): self.log.exception('_get_{}_class: Unable to import ' 'module %s', _class) - raise ManagerException('Unknown {} class: {}' - .format(_type, _class)) + raise ManagerException(f'Unknown {_type} class: {_class}') try: return getattr(module, class_name) except AttributeError: self.log.exception('_get_{}_class: Unable to get class %s ' 'from module %s', class_name, module) - raise ManagerException('Unknown {} class: {}' - .format(_type, _class)) + raise ManagerException(f'Unknown {_type} class: {_class}') def _build_kwargs(self, source): # Build up the arguments we need to pass to the provider @@ -214,8 +212,7 @@ class Manager(object): except KeyError: self.log.exception('Invalid provider config') raise ManagerException('Incorrect provider config, ' - 'missing env var {}' - .format(env_var)) + 'missing env var ' + env_var) except AttributeError: pass kwargs[k] = v @@ -279,7 +276,7 @@ class Manager(object): meta = Record.new(zone, 'octodns-meta', { 'type': 'TXT', 'ttl': 60, - 'value': 'provider={}'.format(target.id) + 'value': f'provider={target.id}', }) zone.add_record(meta, replace=True) try: @@ -322,19 +319,19 @@ class Manager(object): # Check that the source zone is defined. if source_zone not in self.config['zones']: - self.log.error('Invalid alias zone {}, target {} does ' - 'not exist'.format(zone_name, source_zone)) - raise ManagerException('Invalid alias zone {}: ' - 'source zone {} does not exist' - .format(zone_name, source_zone)) + self.log.error(f'Invalid alias zone {zone_name}, ' + f'target {source_zone} does not exist') + raise ManagerException(f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} does ' + 'not exist') # Check that the source zone is not an alias zone itself. if 'alias' in self.config['zones'][source_zone]: - self.log.error('Invalid alias zone {}, target {} is an ' - 'alias zone'.format(zone_name, source_zone)) - raise ManagerException('Invalid alias zone {}: source ' - 'zone {} is an alias zone' - .format(zone_name, source_zone)) + self.log.error(f'Invalid alias zone {zone_name}, ' + f'target {source_zone} is an alias zone') + raise ManagerException(f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} is an ' + 'alias zone') aliased_zones[zone_name] = source_zone continue @@ -343,14 +340,12 @@ class Manager(object): try: sources = config['sources'] except KeyError: - raise ManagerException('Zone {} is missing sources' - .format(zone_name)) + raise ManagerException(f'Zone {zone_name} is missing sources') try: targets = config['targets'] except KeyError: - raise ManagerException('Zone {} is missing targets' - .format(zone_name)) + raise ManagerException(f'Zone {zone_name} is missing targets') processors = config.get('processors', []) @@ -377,8 +372,8 @@ class Manager(object): collected.append(self.processors[processor]) processors = collected except KeyError: - raise ManagerException('Zone {}, unknown processor: {}' - .format(zone_name, processor)) + raise ManagerException(f'Zone {zone_name}, unknown ' + f'processor: {processor}') try: # rather than using a list comprehension, we break this loop @@ -389,21 +384,21 @@ class Manager(object): collected.append(self.providers[source]) sources = collected except KeyError: - raise ManagerException('Zone {}, unknown source: {}' - .format(zone_name, source)) + raise ManagerException(f'Zone {zone_name}, unknown ' + f'source: {source}') try: trgs = [] for target in targets: trg = self.providers[target] if not isinstance(trg, BaseProvider): - raise ManagerException('{} - "{}" does not support ' - 'targeting'.format(trg, target)) + raise ManagerException(f'{trg} - "{target}" does not ' + 'support targeting') trgs.append(trg) targets = trgs except KeyError: - raise ManagerException('Zone {}, unknown target: {}' - .format(zone_name, target)) + raise ManagerException(f'Zone {zone_name}, unknown ' + f'target: {target}') futures.append(self._executor.submit(self._populate_and_plan, zone_name, processors, @@ -427,9 +422,9 @@ class Manager(object): try: desired_config = desired[zone_source] except KeyError: - raise ManagerException('Zone {} cannot be sync without zone ' - '{} sinced it is aliased' - .format(zone_name, zone_source)) + raise ManagerException(f'Zone {zone_name} cannot be sync ' + f'without zone {zone_source} sinced ' + 'it is aliased') futures.append(self._executor.submit( self._populate_and_plan, zone_name, @@ -488,7 +483,7 @@ class Manager(object): a = [self.providers[source] for source in a] b = [self.providers[source] for source in b] except KeyError as e: - raise ManagerException('Unknown source: {}'.format(e.args[0])) + raise ManagerException(f'Unknown source: {e.args[0]}') za = self.get_zone(zone) for source in a: @@ -513,7 +508,7 @@ class Manager(object): try: sources = [self.providers[s] for s in sources] except KeyError as e: - raise ManagerException('Unknown source: {}'.format(e.args[0])) + raise ManagerException(f'Unknown source: {e.args[0]}') clz = YamlProvider if split: @@ -537,15 +532,15 @@ class Manager(object): if source_zone: if source_zone not in self.config['zones']: self.log.exception('Invalid alias zone') - raise ManagerException('Invalid alias zone {}: ' - 'source zone {} does not exist' - .format(zone_name, source_zone)) + raise ManagerException(f'Invalid alias zone {zone_name}: ' + f'source zone {source_zone} does ' + 'not exist') if 'alias' in self.config['zones'][source_zone]: self.log.exception('Invalid alias zone') - raise ManagerException('Invalid alias zone {}: ' - 'source zone {} is an alias zone' - .format(zone_name, source_zone)) + raise ManagerException(f'Invalid alias zone {zone_name}: ' + 'source zone {source_zone} is an ' + 'alias zone') # this is just here to satisfy coverage, see # https://github.com/nedbat/coveragepy/issues/198 @@ -555,8 +550,7 @@ class Manager(object): try: sources = config['sources'] except KeyError: - raise ManagerException('Zone {} is missing sources' - .format(zone_name)) + raise ManagerException(f'Zone {zone_name} is missing sources') try: # rather than using a list comprehension, we break this @@ -567,8 +561,8 @@ class Manager(object): collected.append(self.providers[source]) sources = collected except KeyError: - raise ManagerException('Zone {}, unknown source: {}' - .format(zone_name, source)) + raise ManagerException(f'Zone {zone_name}, unknown source: ' + + source) for source in sources: if isinstance(source, YamlProvider): @@ -581,16 +575,16 @@ class Manager(object): for processor in processors: collected.append(self.processors[processor]) except KeyError: - raise ManagerException('Zone {}, unknown processor: {}' - .format(zone_name, processor)) + raise ManagerException(f'Zone {zone_name}, unknown ' + f'processor: {processor}') def get_zone(self, zone_name): if not zone_name[-1] == '.': - raise ManagerException('Invalid zone name {}, missing ending dot' - .format(zone_name)) + raise ManagerException(f'Invalid zone name {zone_name}, missing ' + 'ending dot') for name, config in self.config['zones'].items(): if name == zone_name: return Zone(name, self.configured_sub_zones(name)) - raise ManagerException('Unknown zone name {}'.format(zone_name)) + raise ManagerException(f'Unknown zone name {zone_name}') diff --git a/octodns/yaml.py b/octodns/yaml.py index 4187199..7e0101c 100644 --- a/octodns/yaml.py +++ b/octodns/yaml.py @@ -26,8 +26,8 @@ class SortEnforcingLoader(SafeLoader): expected = keys_sorted.pop(0) if key != expected: raise ConstructorError(None, None, 'keys out of order: ' - 'expected {} got {} at {}' - .format(expected, key, node.start_mark)) + f'expected {expected} got {key} at ' + + str(node.start_mark)) return dict(ret) diff --git a/octodns/zone.py b/octodns/zone.py index dcc07c3..84a56c7 100644 --- a/octodns/zone.py +++ b/octodns/zone.py @@ -37,8 +37,7 @@ class Zone(object): def __init__(self, name, sub_zones): if not name[-1] == '.': - raise Exception('Invalid zone name {}, missing ending dot' - .format(name)) + raise Exception(f'Invalid zone name {name}, missing ending dot') # Force everything to lowercase just to be safe self.name = text_type(name).lower() if name else name self.sub_zones = sub_zones @@ -47,7 +46,7 @@ class Zone(object): self._records = defaultdict(set) # optional leading . to match empty hostname # optional trailing . b/c some sources don't have it on their fqdn - self._name_re = re.compile(r'\.?{}?$'.format(name)) + self._name_re = re.compile(fr'\.?{name}?$') # Copy-on-write semantics support, when `not None` this property will # point to a location with records for this `Zone`. Once `hydrated` @@ -75,14 +74,13 @@ class Zone(object): if not lenient and last in self.sub_zones: if name != last: # it's a record for something under a sub-zone - raise SubzoneRecordException('Record {} is under a ' - 'managed subzone' - .format(record.fqdn)) + raise SubzoneRecordException(f'Record {record.fqdn} is under ' + 'a managed subzone') elif record._type != 'NS': # It's a non NS record for exactly a sub-zone - raise SubzoneRecordException('Record {} a managed sub-zone ' - 'and not of type NS' - .format(record.fqdn)) + raise SubzoneRecordException(f'Record {record.fqdn} a ' + 'managed sub-zone and not of ' + 'type NS') if replace: # will remove it if it exists @@ -91,16 +89,15 @@ class Zone(object): node = self._records[name] if record in node: # We already have a record at this node of this type - raise DuplicateRecordException('Duplicate record {}, type {}' - .format(record.fqdn, - record._type)) + raise DuplicateRecordException(f'Duplicate record {record.fqdn}, ' + f'type {record._type}') elif not lenient and ((record._type == 'CNAME' and len(node) > 0) or ('CNAME' in [r._type for r in node])): # We're adding a CNAME to existing records or adding to an existing # CNAME - raise InvalidNodeException('Invalid state, CNAME at {} cannot ' - 'coexist with other records' - .format(record.fqdn)) + raise InvalidNodeException('Invalid state, CNAME at ' + f'{record.fqdn} cannot coexist with ' + 'other records') node.add(record) @@ -236,4 +233,4 @@ class Zone(object): return copy def __repr__(self): - return 'Zone<{}>'.format(self.name) + return f'Zone<{self.name}>' From bfbaf16d6a468009f2bd411cd4c557fce744c86a Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Tue, 14 Sep 2021 10:28:23 -0700 Subject: [PATCH 31/34] f-strings for ConstellixProvider --- octodns/provider/constellix.py | 37 ++++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/octodns/provider/constellix.py b/octodns/provider/constellix.py index 3f75650..5ab9531 100644 --- a/octodns/provider/constellix.py +++ b/octodns/provider/constellix.py @@ -27,9 +27,8 @@ class ConstellixClientException(ProviderException): class ConstellixClientBadRequest(ConstellixClientException): def __init__(self, resp): - errors = resp.json()['errors'] - super(ConstellixClientBadRequest, self).__init__( - '\n - {}'.format('\n - '.join(errors))) + errors = '\n - '.join(resp.json()['errors']) + super(ConstellixClientBadRequest, self).__init__(f'\n - {errors}') class ConstellixClientUnauthorized(ConstellixClientException): @@ -73,7 +72,7 @@ class ConstellixClient(object): 'x-cnsdns-requestDate': now } - url = '{}{}'.format(self.BASE, path) + url = f'{self.BASE}{path}' resp = self._sess.request(method, url, headers=headers, params=params, json=data) if resp.status_code == 400: @@ -94,7 +93,7 @@ class ConstellixClient(object): resp = self._request('GET', '/domains').json() zones += resp - self._domains = {'{}.'.format(z['name']): z['id'] for z in zones} + self._domains = {f'{z["name"]}.': z['id'] for z in zones} return self._domains @@ -195,7 +194,7 @@ class ConstellixClient(object): return pool def pool_create(self, data): - path = '/pools/{}'.format(data.get('type')) + path = f'/pools/{data.get("type")}' # This returns a list of items, we want the first one response = self._request('POST', path, data=data).json() @@ -204,7 +203,7 @@ class ConstellixClient(object): return response[0] def pool_update(self, pool_id, data): - path = '/pools/{}/{}'.format(data.get('type'), pool_id) + path = f'/pools/{data.get("type")}/{pool_id}' try: self._request('PUT', path, data=data).json() @@ -358,17 +357,15 @@ class ConstellixProvider(BaseProvider): if 'geoipCountries' in geofilter.keys(): for country_code in geofilter['geoipCountries']: - geos.append('{}-{}'.format( - country_alpha2_to_continent_code(country_code), - country_code - )) + continent_code = \ + country_alpha2_to_continent_code(country_code) + geos.append(f'{continent_code}-{country_code}') if 'regions' in geofilter.keys(): for region in geofilter['regions']: - geos.append('{}-{}-{}'.format( - region['continentCode'], - region['countryCode'], - region['regionCode'])) + geos.append(f'{region["continentCode"]}-' + f'{region["countryCode"]}-' + f'{region["regionCode"]}') rules.append({ 'pool': pool_name, @@ -625,12 +622,8 @@ class ConstellixProvider(BaseProvider): values = pool.data.get('values') # Make a pool name based on zone, record, type and name - generated_pool_name = '{}:{}:{}:{}'.format( - record.zone.name, - record.name, - record._type, - pool_name - ) + generated_pool_name = \ + f'{record.zone.name}:{record.name}:{record._type}:{pool_name}' # OK, pool is valid, let's create it or update it self.log.debug("Creating pool %s", generated_pool_name) @@ -726,7 +719,7 @@ class ConstellixProvider(BaseProvider): def _apply_Create(self, change, domain_name): new = change.new - params_for = getattr(self, '_params_for_{}'.format(new._type)) + params_for = getattr(self, f'_params_for_{new._type}') pools = self._handle_pools(new) for params in params_for(new): From 00f0bf858435a7f55a5454e6c7d0af65ce126ed0 Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 16 Sep 2021 14:22:17 -0700 Subject: [PATCH 32/34] f-strings for BaseProvider supports update --- octodns/provider/base.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/octodns/provider/base.py b/octodns/provider/base.py index 9f03ff5..d45312f 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -53,15 +53,13 @@ class BaseProvider(BaseSource): for record in desired.records: if record._type not in self.SUPPORTS: - msg = '{} records not supported for {}'.format(record._type, - record.fqdn) + msg = f'{record._type} records not supported for {record.fqdn}' fallback = 'omitting record' self.supports_warn_or_except(msg, fallback) desired.remove_record(record) elif getattr(record, 'dynamic', False) and \ not self.SUPPORTS_DYNAMIC: - msg = 'dynamic records not supported for {}'\ - .format(record.fqdn) + msg = f'dynamic records not supported for {record.fqdn}' fallback = 'falling back to simple record' self.supports_warn_or_except(msg, fallback) record = record.copy() From 9156bdaea06f5f9ec2d7f0435dad4f2b5a77d8ea Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 16 Sep 2021 16:16:01 -0700 Subject: [PATCH 33/34] f-strings for tests pass 1 --- tests/test_octodns_provider_azuredns.py | 72 ++++++++--------- tests/test_octodns_provider_digitalocean.py | 4 +- tests/test_octodns_provider_easydns.py | 22 +++--- tests/test_octodns_provider_route53.py | 7 +- tests/test_octodns_provider_selectel.py | 88 ++++++++++----------- tests/test_octodns_provider_yaml.py | 9 +-- tests/test_octodns_record.py | 2 +- 7 files changed, 94 insertions(+), 110 deletions(-) diff --git a/tests/test_octodns_provider_azuredns.py b/tests/test_octodns_provider_azuredns.py index b3b52e5..c201699 100644 --- a/tests/test_octodns_provider_azuredns.py +++ b/tests/test_octodns_provider_azuredns.py @@ -616,7 +616,7 @@ class TestAzureDnsProvider(TestCase): '/resourceGroups/' + rg + \ '/providers/Microsoft.Network/trafficManagerProfiles/' prefix = 'foo--unit--tests' - name_format = prefix + '-{}' + name_format = prefix + '-' id_format = base_id + name_format header = MonitorConfigCustomHeadersItem(name='Host', @@ -628,8 +628,8 @@ class TestAzureDnsProvider(TestCase): profiles = [ Profile( - id=id_format.format('pool-two'), - name=name_format.format('pool-two'), + id=f'{id_format}pool-two', + name=f'{name_format}pool-two', traffic_routing_method='Weighted', dns_config=DnsConfig(ttl=60), monitor_config=monitor, @@ -649,8 +649,8 @@ class TestAzureDnsProvider(TestCase): ], ), Profile( - id=id_format.format('rule-one'), - name=name_format.format('rule-one'), + id=f'{id_format}rule-one', + name=f'{name_format}rule-one', traffic_routing_method='Priority', dns_config=DnsConfig(ttl=60), monitor_config=monitor, @@ -664,7 +664,7 @@ class TestAzureDnsProvider(TestCase): Endpoint( name='two', type=nested, - target_resource_id=id_format.format('pool-two'), + target_resource_id=f'{id_format}pool-two', priority=2, ), Endpoint( @@ -682,8 +682,8 @@ class TestAzureDnsProvider(TestCase): ], ), Profile( - id=id_format.format('rule-two'), - name=name_format.format('rule-two'), + id=f'{id_format}rule-two', + name=f'{name_format}rule-two', traffic_routing_method='Priority', dns_config=DnsConfig(ttl=60), monitor_config=monitor, @@ -691,7 +691,7 @@ class TestAzureDnsProvider(TestCase): Endpoint( name='two', type=nested, - target_resource_id=id_format.format('pool-two'), + target_resource_id=f'{id_format}pool-two', priority=1, ), Endpoint( @@ -719,13 +719,13 @@ class TestAzureDnsProvider(TestCase): geo_mapping=['GEO-AF', 'DE', 'US-CA', 'GEO-AP'], name='one', type=nested, - target_resource_id=id_format.format('rule-one'), + target_resource_id=f'{id_format}rule-one', ), Endpoint( geo_mapping=['WORLD'], name='two', type=nested, - target_resource_id=id_format.format('rule-two'), + target_resource_id=f'{id_format}rule-two', ), ], ), @@ -923,8 +923,8 @@ class TestAzureDnsProvider(TestCase): tm_id = provider._profile_name_to_id root_profile_name = _root_traffic_manager_name(record) extra_profile = Profile( - id=tm_id('{}-pool-random'.format(root_profile_name)), - name='{}-pool-random'.format(root_profile_name), + id=tm_id(f'{root_profile_name}-pool-random'), + name=f'{root_profile_name}-pool-random', traffic_routing_method='Weighted', dns_config=sample_profile.dns_config, monitor_config=sample_profile.monitor_config, @@ -1150,7 +1150,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1191,7 +1191,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=tm_id(tm_suffix)), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' with self.assertRaises(AzureException) as ctx: provider._populate_record(zone, azrecord) self.assertTrue(text_type(ctx).startswith( @@ -1261,7 +1261,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1320,7 +1320,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1416,7 +1416,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1496,7 +1496,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1604,7 +1604,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1711,7 +1711,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1857,7 +1857,7 @@ class TestAzureDnsProvider(TestCase): azrecord = RecordSet( ttl=60, target_resource=SubResource(id=None)) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.values, ['255.255.255.255']) @@ -1870,7 +1870,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1939,7 +1939,7 @@ class TestAzureDnsProvider(TestCase): azrecord = RecordSet( ttl=60, target_resource=SubResource(id=None)) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.values, ['::1']) @@ -1951,7 +1951,7 @@ class TestAzureDnsProvider(TestCase): target_resource=SubResource(id=profiles[-1].id), ) azrecord.name = record.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record._type) + azrecord.type = f'Microsoft.Network/dnszones/{record._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.dynamic._data(), record.dynamic._data()) @@ -1969,8 +1969,8 @@ class TestAzureDnsProvider(TestCase): prefix = 'foo--unit--tests' expected_seen = { - prefix, '{}-pool-two'.format(prefix), - '{}-rule-one'.format(prefix), '{}-rule-two'.format(prefix), + prefix, f'{prefix}-pool-two', f'{prefix}-rule-one', + f'{prefix}-rule-two', } # test no change @@ -1997,9 +1997,7 @@ class TestAzureDnsProvider(TestCase): tm_sync.assert_called_once() # test that new profile was successfully inserted in cache - new_profile = provider._get_tm_profile_by_name( - '{}-pool-two'.format(prefix) - ) + new_profile = provider._get_tm_profile_by_name(f'{prefix}-pool-two') self.assertEqual(new_profile.endpoints[0].weight, 14) def test_sync_traffic_managers_duplicate(self): @@ -2028,8 +2026,8 @@ class TestAzureDnsProvider(TestCase): prefix2 = _root_traffic_manager_name(record2) tm_id = provider._profile_name_to_id extra_profile = Profile( - id=tm_id('{}-pool-random'.format(prefix2)), - name='{}-pool-random'.format(prefix2), + id=tm_id(f'{prefix2}-pool-random'), + name=f'{prefix2}-pool-random', traffic_routing_method='Weighted', dns_config=sample_profile.dns_config, monitor_config=sample_profile.monitor_config, @@ -2042,8 +2040,8 @@ class TestAzureDnsProvider(TestCase): # implicitly asserts that non-matching profile is not included prefix = _root_traffic_manager_name(record) self.assertEqual(provider._find_traffic_managers(record), { - prefix, '{}-pool-two'.format(prefix), - '{}-rule-one'.format(prefix), '{}-rule-two'.format(prefix), + prefix, f'{prefix}-pool-two', f'{prefix}-rule-one', + f'{prefix}-rule-two', }) def test_traffic_manager_gc(self): @@ -2158,8 +2156,8 @@ class TestAzureDnsProvider(TestCase): tm_id = provider._profile_name_to_id root_profile_name = _root_traffic_manager_name(dynamic_record) extra_profile = Profile( - id=tm_id('{}-pool-random'.format(root_profile_name)), - name='{}-pool-random'.format(root_profile_name), + id=tm_id(f'{root_profile_name}-pool-random'), + name=f'{root_profile_name}-pool-random', traffic_routing_method='Weighted', dns_config=sample_profile.dns_config, monitor_config=sample_profile.monitor_config, @@ -2183,7 +2181,7 @@ class TestAzureDnsProvider(TestCase): azrecord = RecordSet( ttl=record1.ttl, target_resource=SubResource(id=None)) azrecord.name = record1.name or '@' - azrecord.type = 'Microsoft.Network/dnszones/{}'.format(record1._type) + azrecord.type = f'Microsoft.Network/dnszones/{record1._type}' record2 = provider._populate_record(zone, azrecord) self.assertEqual(record2.value, 'iam.invalid.') diff --git a/tests/test_octodns_provider_digitalocean.py b/tests/test_octodns_provider_digitalocean.py index 2f28fff..83692aa 100644 --- a/tests/test_octodns_provider_digitalocean.py +++ b/tests/test_octodns_provider_digitalocean.py @@ -77,9 +77,9 @@ class TestDigitalOceanProvider(TestCase): base = 'https://api.digitalocean.com/v2/domains/unit.tests/' \ 'records?page=' with open('tests/fixtures/digitalocean-page-1.json') as fh: - mock.get('{}{}'.format(base, 1), text=fh.read()) + mock.get(f'{base}1', text=fh.read()) with open('tests/fixtures/digitalocean-page-2.json') as fh: - mock.get('{}{}'.format(base, 2), text=fh.read()) + mock.get(f'{base}2', text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_easydns.py b/tests/test_octodns_provider_easydns.py index 9b50024..cab40f1 100644 --- a/tests/test_octodns_provider_easydns.py +++ b/tests/test_octodns_provider_easydns.py @@ -73,11 +73,9 @@ class TestEasyDNSProvider(TestCase): with requests_mock() as mock: base = 'https://rest.easydns.net/zones/records/' with open('tests/fixtures/easydns-records.json') as fh: - mock.get('{}{}'.format(base, 'parsed/unit.tests'), - text=fh.read()) + mock.get(f'{base}parsed/unit.tests', text=fh.read()) with open('tests/fixtures/easydns-records.json') as fh: - mock.get('{}{}'.format(base, 'all/unit.tests'), - text=fh.read()) + mock.get(f'{base}all/unit.tests', text=fh.read()) provider.populate(zone) self.assertEquals(15, len(zone.records)) @@ -97,7 +95,7 @@ class TestEasyDNSProvider(TestCase): with requests_mock() as mock: base = 'https://rest.easydns.net/' - mock.get('{}{}'.format(base, 'domain/unit.tests'), status_code=400, + mock.get(f'{base}domain/unit.tests', status_code=400, text='{"id":"not_found","message":"The resource you ' 'were accessing could not be found."}') @@ -120,18 +118,16 @@ class TestEasyDNSProvider(TestCase): with requests_mock() as mock: base = 'https://rest.easydns.net/' - mock.get('{}{}'.format(base, 'domain/unit.tests'), status_code=404, + mock.get(f'{base}domain/unit.tests', status_code=404, text='{"id":"not_found","message":"The resource you ' 'were accessing could not be found."}') - mock.put('{}{}'.format(base, 'domains/add/unit.tests'), - status_code=200, + mock.put(f'{base}domains/add/unit.tests', status_code=200, text='{"id":"OK","message":"Zone created."}') - mock.get('{}{}'.format(base, 'zones/records/parsed/unit.tests'), + mock.get(f'{base}zones/records/parsed/unit.tests', status_code=404, text='{"id":"not_found","message":"The resource you ' 'were accessing could not be found."}') - mock.get('{}{}'.format(base, 'zones/records/all/unit.tests'), - status_code=404, + mock.get(f'{base}zones/records/all/unit.tests', status_code=404, text='{"id":"not_found","message":"The resource you ' 'were accessing could not be found."}') @@ -188,9 +184,9 @@ class TestEasyDNSProvider(TestCase): } with requests_mock() as mock: base = 'https://rest.easydns.net/' - mock.put('{}{}'.format(base, 'domains/add/unit.tests'), + mock.put(f'{base}domains/add/unit.tests', status_code=201, text='{"id":"OK"}') - mock.get('{}{}'.format(base, 'zones/records/all/unit.tests'), + mock.get(f'{base}zones/records/all/unit.tests', text=json.dumps(domain_after_creation)) mock.delete(ANY, text='{"id":"OK"}') provider._client.domain_create('unit.tests') diff --git a/tests/test_octodns_provider_route53.py b/tests/test_octodns_provider_route53.py index a80122e..8bc4562 100644 --- a/tests/test_octodns_provider_route53.py +++ b/tests/test_octodns_provider_route53.py @@ -291,8 +291,8 @@ class TestRoute53Provider(TestCase): record = Record.new(expected, name, data) expected.add_record(record) - caller_ref = '{}:A:unit.tests.:1324' \ - .format(Route53Provider.HEALTH_CHECK_VERSION) + caller_ref = f'{Route53Provider.HEALTH_CHECK_VERSION}:A:unit.tests.:1324' + health_checks = [{ 'Id': '42', 'CallerReference': caller_ref, @@ -1243,8 +1243,7 @@ class TestRoute53Provider(TestCase): provider, stubber = self._get_stubbed_provider() # No match based on type - caller_ref = \ - '{}:AAAA:foo1234'.format(Route53Provider.HEALTH_CHECK_VERSION) + caller_ref = f'{Route53Provider.HEALTH_CHECK_VERSION}:AAAA:foo1234' health_checks = [{ 'Id': '42', # No match based on version diff --git a/tests/test_octodns_provider_selectel.py b/tests/test_octodns_provider_selectel.py index 7ad1e6b..894f8d2 100644 --- a/tests/test_octodns_provider_selectel.py +++ b/tests/test_octodns_provider_selectel.py @@ -196,12 +196,12 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_populate(self, fake_http): zone = Zone('unit.tests.', []) - fake_http.get('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/unit.tests/records/', json=self.api_record) - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': str(len(self.api_record))}) - fake_http.head('{}/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) provider = SelectelProvider(123, 'secret_token') @@ -220,12 +220,12 @@ class TestSelectelProvider(TestCase): "email": "support@unit.tests"}) zone = Zone('unit.tests.', []) - fake_http.get('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/unit.tests/records/', json=more_record) - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': str(len(self.api_record))}) - fake_http.head('{}/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) zone.add_record(Record.new(self.zone, 'unsup', { @@ -249,14 +249,13 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_apply(self, fake_http): - fake_http.get('{}/unit.tests/records/'.format(self.API_URL), - json=list()) - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/unit.tests/records/', json=list()) + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': '0'}) - fake_http.head('{}/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) - fake_http.post('{}/100000/records/'.format(self.API_URL), json=list()) + fake_http.post(f'{self.API_URL}/100000/records/', json=list()) provider = SelectelProvider(123, 'test_token') @@ -271,8 +270,8 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_domain_list(self, fake_http): - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.head('{}/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) expected = {'unit.tests': self.domain[0]} @@ -283,8 +282,8 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_authentication_fail(self, fake_http): - fake_http.get('{}/'.format(self.API_URL), status_code=401) - fake_http.head('{}/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', status_code=401) + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) with self.assertRaises(Exception) as ctx: @@ -294,20 +293,17 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_not_exist_domain(self, fake_http): - fake_http.get('{}/'.format(self.API_URL), status_code=404, json='') - fake_http.head('{}/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', status_code=404, json='') + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) - fake_http.post('{}/'.format(self.API_URL), - json={"name": "unit.tests", - "create_date": 1507154178, - "id": 100000}) - fake_http.get('{}/unit.tests/records/'.format(self.API_URL), - json=list()) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.post(f'{self.API_URL}/', json={"name": "unit.tests", + "create_date": 1507154178, + "id": 100000}) + fake_http.get(f'{self.API_URL}/unit.tests/records/', json=list()) + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': str(len(self.api_record))}) - fake_http.post('{}/100000/records/'.format(self.API_URL), - json=list()) + fake_http.post(f'{self.API_URL}/100000/records/', json=list()) provider = SelectelProvider(123, 'test_token') @@ -322,11 +318,11 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_delete_no_exist_record(self, fake_http): - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.get('{}/100000/records/'.format(self.API_URL), json=list()) - fake_http.head('{}/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.get(f'{self.API_URL}/100000/records/', json=list()) + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': '0'}) provider = SelectelProvider(123, 'test_token') @@ -348,23 +344,19 @@ class TestSelectelProvider(TestCase): "type": "A", "id": 100002, "name": "unit.tests"}] # exist - fake_http.get('{}/unit.tests/records/'.format(self.API_URL), - json=exist_record) - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.get('{}/100000/records/'.format(self.API_URL), - json=exist_record) - fake_http.head('{}/unit.tests/records/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/unit.tests/records/', json=exist_record) + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.get(f'{self.API_URL}/100000/records/', json=exist_record) + fake_http.head(f'{self.API_URL}/unit.tests/records/', headers={'X-Total-Count': str(len(exist_record))}) - fake_http.head('{}/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) - fake_http.head('{}/100000/records/'.format(self.API_URL), + fake_http.head(f'{self.API_URL}/100000/records/', headers={'X-Total-Count': str(len(exist_record))}) - fake_http.post('{}/100000/records/'.format(self.API_URL), + fake_http.post(f'{self.API_URL}/100000/records/', json=list()) - fake_http.delete('{}/100000/records/100001'.format(self.API_URL), - text="") - fake_http.delete('{}/100000/records/100002'.format(self.API_URL), - text="") + fake_http.delete(f'{self.API_URL}/100000/records/100001', text="") + fake_http.delete(f'{self.API_URL}/100000/records/100002', text="") provider = SelectelProvider(123, 'test_token') @@ -379,8 +371,8 @@ class TestSelectelProvider(TestCase): @requests_mock.Mocker() def test_include_change_returns_false(self, fake_http): - fake_http.get('{}/'.format(self.API_URL), json=self.domain) - fake_http.head('{}/'.format(self.API_URL), + fake_http.get(f'{self.API_URL}/', json=self.domain) + fake_http.head(f'{self.API_URL}/', headers={'X-Total-Count': str(len(self.domain))}) provider = SelectelProvider(123, 'test_token') zone = Zone('unit.tests.', []) diff --git a/tests/test_octodns_provider_yaml.py b/tests/test_octodns_provider_yaml.py index 7e4f6f7..d6ae1d1 100644 --- a/tests/test_octodns_provider_yaml.py +++ b/tests/test_octodns_provider_yaml.py @@ -309,7 +309,7 @@ class TestSplitYamlProvider(TestCase): # ensure correctness. for record_name in ('_srv._tcp', 'mx', 'naptr', 'sub', 'txt', 'urlfwd'): - yaml_file = join(zone_dir, '{}.yaml'.format(record_name)) + yaml_file = join(zone_dir, f'{record_name}.yaml') self.assertTrue(isfile(yaml_file)) with open(yaml_file) as fh: data = safe_load(fh.read()) @@ -318,7 +318,7 @@ class TestSplitYamlProvider(TestCase): # These are stored as singular "value." Again, check each file. for record_name in ('aaaa', 'cname', 'dname', 'included', 'ptr', 'spf', 'www.sub', 'www'): - yaml_file = join(zone_dir, '{}.yaml'.format(record_name)) + yaml_file = join(zone_dir, f'{record_name}.yaml') self.assertTrue(isfile(yaml_file)) with open(yaml_file) as fh: data = safe_load(fh.read()) @@ -327,7 +327,7 @@ class TestSplitYamlProvider(TestCase): # Again with the plural, this time checking dynamic.tests. for record_name in ('a', 'aaaa', 'real-ish-a'): yaml_file = join( - dynamic_zone_dir, '{}.yaml'.format(record_name)) + dynamic_zone_dir, f'{record_name}.yaml') self.assertTrue(isfile(yaml_file)) with open(yaml_file) as fh: data = safe_load(fh.read()) @@ -337,8 +337,7 @@ class TestSplitYamlProvider(TestCase): # Singular again. for record_name in ('cname', 'simple-weighted'): - yaml_file = join( - dynamic_zone_dir, '{}.yaml'.format(record_name)) + yaml_file = join(dynamic_zone_dir, f'{record_name}.yaml') self.assertTrue(isfile(yaml_file)) with open(yaml_file) as fh: data = safe_load(fh.read()) diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index c848853..9cbee50 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -2664,7 +2664,7 @@ class TestRecordValidation(TestCase): 'ttl': 600, 'value': v }) - self.assertEquals(['missing {}'.format(k)], ctx.exception.reasons) + self.assertEquals([f'missing {k}'], ctx.exception.reasons) # non-int order v = dict(value) From 775917f4b9e910910befd2d5269ee7871310d5ed Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 16 Sep 2021 19:55:22 -0700 Subject: [PATCH 34/34] f-strings for the rest of the tests --- tests/test_octodns_processor_ownership.py | 2 +- tests/test_octodns_provider_cloudflare.py | 23 ++++----- tests/test_octodns_provider_constellix.py | 12 ++--- tests/test_octodns_provider_dnsimple.py | 4 +- tests/test_octodns_provider_dnsmadeeasy.py | 5 +- tests/test_octodns_provider_gcore.py | 2 +- tests/test_octodns_provider_googlecloud.py | 5 +- tests/test_octodns_provider_hetzner.py | 4 +- tests/test_octodns_provider_ns1.py | 10 ++-- tests/test_octodns_provider_transip.py | 3 +- tests/test_octodns_provider_ultra.py | 54 ++++++++++------------ tests/test_octodns_source_envvar.py | 4 +- 12 files changed, 55 insertions(+), 73 deletions(-) diff --git a/tests/test_octodns_processor_ownership.py b/tests/test_octodns_processor_ownership.py index e6b248b..35074f7 100644 --- a/tests/test_octodns_processor_ownership.py +++ b/tests/test_octodns_processor_ownership.py @@ -129,7 +129,7 @@ class TestOwnershipProcessor(TestCase): # two delete changes. the_a = records['the-a'] plan.existing.add_record(the_a) - name = '{}.a.the-a'.format(ownership.txt_name) + name = f'{ownership.txt_name}.a.the-a' the_a_ownership = Record.new(zone, name, { 'ttl': 30, 'type': 'TXT', diff --git a/tests/test_octodns_provider_cloudflare.py b/tests/test_octodns_provider_cloudflare.py index 2cc11cb..30ef9ca 100644 --- a/tests/test_octodns_provider_cloudflare.py +++ b/tests/test_octodns_provider_cloudflare.py @@ -157,36 +157,31 @@ class TestCloudflareProvider(TestCase): # zones with open('tests/fixtures/cloudflare-zones-page-1.json') as fh: - mock.get('{}?page=1'.format(base), status_code=200, - text=fh.read()) + mock.get(f'{base}?page=1', status_code=200, text=fh.read()) with open('tests/fixtures/cloudflare-zones-page-2.json') as fh: - mock.get('{}?page=2'.format(base), status_code=200, - text=fh.read()) - mock.get('{}?page=3'.format(base), status_code=200, + mock.get(f'{base}?page=2', status_code=200, text=fh.read()) + mock.get(f'{base}?page=3', status_code=200, json={'result': [], 'result_info': {'count': 0, 'per_page': 0}}) - base = '{}/234234243423aaabb334342aaa343435'.format(base) + base = f'{base}/234234243423aaabb334342aaa343435' # pagerules/URLFWD with open('tests/fixtures/cloudflare-pagerules.json') as fh: - mock.get('{}/pagerules?status=active'.format(base), + mock.get(f'{base}/pagerules?status=active', status_code=200, text=fh.read()) # records - base = '{}/dns_records'.format(base) + base = f'{base}/dns_records' with open('tests/fixtures/cloudflare-dns_records-' 'page-1.json') as fh: - mock.get('{}?page=1'.format(base), status_code=200, - text=fh.read()) + mock.get(f'{base}?page=1', status_code=200, text=fh.read()) with open('tests/fixtures/cloudflare-dns_records-' 'page-2.json') as fh: - mock.get('{}?page=2'.format(base), status_code=200, - text=fh.read()) + mock.get(f'{base}?page=2', status_code=200, text=fh.read()) with open('tests/fixtures/cloudflare-dns_records-' 'page-3.json') as fh: - mock.get('{}?page=3'.format(base), status_code=200, - text=fh.read()) + mock.get(f'{base}?page=3', status_code=200, text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_constellix.py b/tests/test_octodns_provider_constellix.py index 75aa07f..e38f0fa 100644 --- a/tests/test_octodns_provider_constellix.py +++ b/tests/test_octodns_provider_constellix.py @@ -192,17 +192,13 @@ class TestConstellixProvider(TestCase): with requests_mock() as mock: base = 'https://api.dns.constellix.com/v1' with open('tests/fixtures/constellix-domains.json') as fh: - mock.get('{}{}'.format(base, '/domains'), - text=fh.read()) + mock.get(f'{base}/domains', text=fh.read()) with open('tests/fixtures/constellix-records.json') as fh: - mock.get('{}{}'.format(base, '/domains/123123/records'), - text=fh.read()) + mock.get(f'{base}/domains/123123/records', text=fh.read()) with open('tests/fixtures/constellix-pools.json') as fh: - mock.get('{}{}'.format(base, '/pools/A'), - text=fh.read()) + mock.get(f'{base}/pools/A', text=fh.read()) with open('tests/fixtures/constellix-geofilters.json') as fh: - mock.get('{}{}'.format(base, '/geoFilters'), - text=fh.read()) + mock.get(f'{base}/geoFilters', text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_dnsimple.py b/tests/test_octodns_provider_dnsimple.py index 0b8d209..2039a6b 100644 --- a/tests/test_octodns_provider_dnsimple.py +++ b/tests/test_octodns_provider_dnsimple.py @@ -79,9 +79,9 @@ class TestDnsimpleProvider(TestCase): base = 'https://api.dnsimple.com/v2/42/zones/unit.tests/' \ 'records?page=' with open('tests/fixtures/dnsimple-page-1.json') as fh: - mock.get('{}{}'.format(base, 1), text=fh.read()) + mock.get(f'{base}1', text=fh.read()) with open('tests/fixtures/dnsimple-page-2.json') as fh: - mock.get('{}{}'.format(base, 2), text=fh.read()) + mock.get(f'{base}2', text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_dnsmadeeasy.py b/tests/test_octodns_provider_dnsmadeeasy.py index 9efc81d..7922ad2 100644 --- a/tests/test_octodns_provider_dnsmadeeasy.py +++ b/tests/test_octodns_provider_dnsmadeeasy.py @@ -95,10 +95,9 @@ class TestDnsMadeEasyProvider(TestCase): with requests_mock() as mock: base = 'https://api.dnsmadeeasy.com/V2.0/dns/managed' with open('tests/fixtures/dnsmadeeasy-domains.json') as fh: - mock.get('{}{}'.format(base, '/'), text=fh.read()) + mock.get(f'{base}/', text=fh.read()) with open('tests/fixtures/dnsmadeeasy-records.json') as fh: - mock.get('{}{}'.format(base, '/123123/records'), - text=fh.read()) + mock.get(f'{base}/123123/records', text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_gcore.py b/tests/test_octodns_provider_gcore.py index 2151440..dc9b013 100644 --- a/tests/test_octodns_provider_gcore.py +++ b/tests/test_octodns_provider_gcore.py @@ -195,7 +195,7 @@ class TestGCoreProvider(TestCase): str(ctx.exception).startswith( "filter is enabled, but no pools where built for" ), - "{} - is not start from desired text".format(ctx.exception), + f"{ctx.exception} - is not start from desired text", ) def test_apply(self): diff --git a/tests/test_octodns_provider_googlecloud.py b/tests/test_octodns_provider_googlecloud.py index e642668..9348ea1 100644 --- a/tests/test_octodns_provider_googlecloud.py +++ b/tests/test_octodns_provider_googlecloud.py @@ -156,8 +156,7 @@ class DummyResourceRecordSet: return False def __repr__(self): - return "{} {} {} {!s}"\ - .format(self.name, self.record_type, self.ttl, self.rrdatas) + return f"{self.name} {self.record_type} {self.ttl} {self.rrdatas}" def __hash__(self): return hash(repr(self)) @@ -419,7 +418,7 @@ class TestGoogleCloudProvider(TestCase): dummy_gcloud_zone = DummyGoogleCloudZone("unit.tests") for octo_record in octo_records: _rrset_func = getattr( - provider, '_rrset_for_{}'.format(octo_record._type)) + provider, f'_rrset_for_{octo_record._type}') self.assertEqual( _rrset_func(dummy_gcloud_zone, octo_record).record_type, octo_record._type diff --git a/tests/test_octodns_provider_hetzner.py b/tests/test_octodns_provider_hetzner.py index 218a6b2..12d845f 100644 --- a/tests/test_octodns_provider_hetzner.py +++ b/tests/test_octodns_provider_hetzner.py @@ -68,9 +68,9 @@ class TestHetznerProvider(TestCase): with requests_mock() as mock: base = provider._client.BASE_URL with open('tests/fixtures/hetzner-zones.json') as fh: - mock.get('{}/zones'.format(base), text=fh.read()) + mock.get(f'{base}/zones', text=fh.read()) with open('tests/fixtures/hetzner-records.json') as fh: - mock.get('{}/records'.format(base), text=fh.read()) + mock.get(f'{base}/records', text=fh.read()) zone = Zone('unit.tests.', []) provider.populate(zone) diff --git a/tests/test_octodns_provider_ns1.py b/tests/test_octodns_provider_ns1.py index de6bdc9..5146573 100644 --- a/tests/test_octodns_provider_ns1.py +++ b/tests/test_octodns_provider_ns1.py @@ -1653,7 +1653,7 @@ class TestNs1ProviderDynamic(TestCase): 'meta': { 'priority': 1, 'weight': 12, - 'note': 'from:{}'.format(catchall_pool_name), + 'note': f'from:{catchall_pool_name}', }, 'region': catchall_pool_name, }, { @@ -1774,8 +1774,7 @@ class TestNs1ProviderDynamic(TestCase): partial_oc_cntry_list data4 = provider._data_for_A('A', ns1_record) for c in partial_oc_cntry_list: - self.assertTrue( - 'OC-{}'.format(c) in data4['dynamic']['rules'][0]['geos']) + self.assertTrue(f'OC-{c}' in data4['dynamic']['rules'][0]['geos']) # NA test cases # 1. Full list of countries should return 'NA' in geos @@ -1792,8 +1791,7 @@ class TestNs1ProviderDynamic(TestCase): partial_na_cntry_list data6 = provider._data_for_A('A', ns1_record) for c in partial_na_cntry_list: - self.assertTrue( - 'NA-{}'.format(c) in data6['dynamic']['rules'][0]['geos']) + self.assertTrue(f'NA-{c}' in data6['dynamic']['rules'][0]['geos']) # Test out fallback only pools and new-style notes ns1_record = { @@ -1919,7 +1917,7 @@ class TestNs1ProviderDynamic(TestCase): 'meta': { 'priority': 1, 'weight': 12, - 'note': 'from:{}'.format(catchall_pool_name), + 'note': f'from:{catchall_pool_name}', }, 'region': catchall_pool_name, }, { diff --git a/tests/test_octodns_provider_transip.py b/tests/test_octodns_provider_transip.py index 8a2e11a..e6d384d 100644 --- a/tests/test_octodns_provider_transip.py +++ b/tests/test_octodns_provider_transip.py @@ -45,8 +45,7 @@ class MockDomainService(object): _dns_entries = [] for record in records: if record._type in provider.SUPPORTS: - entries_for = getattr(provider, - '_entries_for_{}'.format(record._type)) + entries_for = getattr(provider, f'_entries_for_{record._type}') # Root records have '@' as name name = record.name diff --git a/tests/test_octodns_provider_ultra.py b/tests/test_octodns_provider_ultra.py index a22a489..ec18ba3 100644 --- a/tests/test_octodns_provider_ultra.py +++ b/tests/test_octodns_provider_ultra.py @@ -41,7 +41,7 @@ class TestUltraProvider(TestCase): # Bad Auth with requests_mock() as mock: - mock.post('{}{}'.format(self.host, path), status_code=401, + mock.post(f'{self.host}{path}', status_code=401, text='{"errorCode": 60001}') with self.assertRaises(Exception) as ctx: UltraProvider('test', 'account', 'user', 'wrongpass') @@ -50,7 +50,7 @@ class TestUltraProvider(TestCase): # Good Auth with requests_mock() as mock: headers = {'Content-Type': 'application/x-www-form-urlencoded'} - mock.post('{}{}'.format(self.host, path), status_code=200, + mock.post(f'{self.host}{path}', status_code=200, request_headers=headers, text='{"token type": "Bearer", "refresh_token": "abc", ' '"access_token":"123", "expires_in": "3600"}') @@ -67,7 +67,7 @@ class TestUltraProvider(TestCase): # Test authorization issue with requests_mock() as mock: - mock.get('{}{}'.format(self.host, path), status_code=400, + mock.get(f'{self.host}{path}', status_code=400, json={"errorCode": 60004, "errorMessage": "Authorization Header required"}) with self.assertRaises(HTTPError) as ctx: @@ -76,7 +76,7 @@ class TestUltraProvider(TestCase): # Test no zones exist error with requests_mock() as mock: - mock.get('{}{}'.format(self.host, path), status_code=404, + mock.get(f'{self.host}{path}', status_code=404, headers={'Authorization': 'Bearer 123'}, json=self.empty_body) zones = provider.zones @@ -109,7 +109,7 @@ class TestUltraProvider(TestCase): ] } - mock.get('{}{}'.format(self.host, path), status_code=200, + mock.get(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}, json=payload) zones = provider.zones @@ -120,14 +120,14 @@ class TestUltraProvider(TestCase): # Test different paging behavior provider._zones = None with requests_mock() as mock: - mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0' - .format(self.host, path), status_code=200, + mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&' + 'offset=0', status_code=200, json={"resultInfo": {"totalCount": 15, "offset": 0, "returnedCount": 10}, "zones": []}) - mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=10' - .format(self.host, path), status_code=200, + mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY' + '&offset=10', status_code=200, json={"resultInfo": {"totalCount": 15, "offset": 10, "returnedCount": 5}, @@ -141,7 +141,7 @@ class TestUltraProvider(TestCase): payload = {'a': 1} with requests_mock() as mock: - mock.get('{}{}'.format(self.host, path), status_code=401, + mock.get(f'{self.host}{path}', status_code=401, headers={'Authorization': 'Bearer 123'}, json={}) with self.assertRaises(Exception) as ctx: provider._get(path) @@ -149,37 +149,37 @@ class TestUltraProvider(TestCase): # Test all GET patterns with requests_mock() as mock: - mock.get('{}{}'.format(self.host, path), status_code=200, + mock.get(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}, json=payload) provider._get(path, json=payload) - mock.get('{}{}?a=1'.format(self.host, path), status_code=200, + mock.get(f'{self.host}{path}?a=1', status_code=200, headers={'Authorization': 'Bearer 123'}) provider._get(path, params=payload, json_response=False) # Test all POST patterns with requests_mock() as mock: - mock.post('{}{}'.format(self.host, path), status_code=200, + mock.post(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}, json=payload) provider._post(path, json=payload) - mock.post('{}{}'.format(self.host, path), status_code=200, + mock.post(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}, text="{'a':1}") provider._post(path, data=payload, json_response=False) # Test all PUT patterns with requests_mock() as mock: - mock.put('{}{}'.format(self.host, path), status_code=200, + mock.put(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}, json=payload) provider._put(path, json=payload) # Test all DELETE patterns with requests_mock() as mock: - mock.delete('{}{}'.format(self.host, path), status_code=200, + mock.delete(f'{self.host}{path}', status_code=200, headers={'Authorization': 'Bearer 123'}) provider._delete(path, json_response=False) @@ -221,10 +221,9 @@ class TestUltraProvider(TestCase): zone_path = '/v2/zones' rec_path = '/v2/zones/octodns1.test./rrsets' with requests_mock() as mock: - mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0' - .format(self.host, zone_path), - status_code=200, json=zone_payload) - mock.get('{}{}?offset=0&limit=100'.format(self.host, rec_path), + mock.get(f'{self.host}{zone_path}?limit=100&q=zone_type%3APRIMARY&' + 'offset=0', status_code=200, json=zone_payload) + mock.get(f'{self.host}{rec_path}?offset=0&limit=100', status_code=200, json=records_payload) zone = Zone('octodns1.test.', []) @@ -257,21 +256,18 @@ class TestUltraProvider(TestCase): path = '/v2/zones' with requests_mock() as mock: with open('tests/fixtures/ultra-zones-page-1.json') as fh: - mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=0' - .format(self.host, path), - status_code=200, text=fh.read()) + mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&' + 'offset=0', status_code=200, text=fh.read()) with open('tests/fixtures/ultra-zones-page-2.json') as fh: - mock.get('{}{}?limit=100&q=zone_type%3APRIMARY&offset=10' - .format(self.host, path), - status_code=200, text=fh.read()) + mock.get(f'{self.host}{path}?limit=100&q=zone_type%3APRIMARY&' + 'offset=10', status_code=200, text=fh.read()) with open('tests/fixtures/ultra-records-page-1.json') as fh: rec_path = '/v2/zones/octodns1.test./rrsets' - mock.get('{}{}?offset=0&limit=100'.format(self.host, rec_path), + mock.get(f'{self.host}{rec_path}?offset=0&limit=100', status_code=200, text=fh.read()) with open('tests/fixtures/ultra-records-page-2.json') as fh: rec_path = '/v2/zones/octodns1.test./rrsets' - mock.get('{}{}?offset=10&limit=100' - .format(self.host, rec_path), + mock.get(f'{self.host}{rec_path}?offset=10&limit=100', status_code=200, text=fh.read()) zone = Zone('octodns1.test.', []) diff --git a/tests/test_octodns_source_envvar.py b/tests/test_octodns_source_envvar.py index ac66a22..84c5fab 100644 --- a/tests/test_octodns_source_envvar.py +++ b/tests/test_octodns_source_envvar.py @@ -14,7 +14,7 @@ class TestEnvVarSource(TestCase): source = EnvVarSource('testid', envvar, 'recordname', ttl=120) with self.assertRaises(EnvironmentVariableNotFoundException) as ctx: source._read_variable() - msg = 'Unknown environment variable {}'.format(envvar) + msg = f'Unknown environment variable {envvar}' self.assertEquals(msg, text_type(ctx.exception)) with patch.dict('os.environ', {envvar: 'testvalue'}): @@ -35,7 +35,7 @@ class TestEnvVarSource(TestCase): self.assertEquals(1, len(zone.records)) record = list(zone.records)[0] self.assertEquals(name, record.name) - self.assertEquals('{}.{}'.format(name, zone_name), record.fqdn) + self.assertEquals(f'{name}.{zone_name}', record.fqdn) self.assertEquals('TXT', record._type) self.assertEquals(1, len(record.values)) self.assertEquals(value, record.values[0])