diff --git a/python/nav/alertengine/dispatchers/sms_dispatcher.py b/python/nav/alertengine/dispatchers/sms_dispatcher.py index 374d1df439..15d3c14f5e 100644 --- a/python/nav/alertengine/dispatchers/sms_dispatcher.py +++ b/python/nav/alertengine/dispatchers/sms_dispatcher.py @@ -73,6 +73,4 @@ def get_fallback_message(self, alert, language, message_type): @staticmethod def is_valid_address(address): - if address.startswith("+"): - return address[1:].isdigit() - return address.isdigit() + return address.removeprefix("+").isdigit() diff --git a/python/nav/bin/navmain.py b/python/nav/bin/navmain.py index b69c5bce93..44fde7bab5 100755 --- a/python/nav/bin/navmain.py +++ b/python/nav/bin/navmain.py @@ -214,7 +214,7 @@ def _service_printer(service): kind = service.__class__.__name__ if kind.endswith("Service"): - kind = kind[:-7].lower() + kind = kind.removesuffix("Service").lower() kind = "({})".format(kind) kind = "{:>8}".format(kind) colors.print_color(kind, colors.COLOR_YELLOW, newline=False) diff --git a/python/nav/django/validators.py b/python/nav/django/validators.py index 7a73d3f692..ed800d8cbb 100644 --- a/python/nav/django/validators.py +++ b/python/nav/django/validators.py @@ -26,8 +26,7 @@ def is_valid_point_string(point_string): if len(point_string.split(',')) == 2: - if point_string.startswith('(') and point_string.endswith(')'): - point_string = point_string[1:-1] + point_string = point_string.removeprefix("(").removesuffix(")") x_point, y_point = point_string.split(',') try: Decimal(x_point.strip()) diff --git a/python/nav/ipdevpoll/config.py b/python/nav/ipdevpoll/config.py index 5bb8dc1bf5..ba725bf76e 100644 --- a/python/nav/ipdevpoll/config.py +++ b/python/nav/ipdevpoll/config.py @@ -146,7 +146,7 @@ def __init__(self, name, interval, intensity, plugins, description=''): def from_config_section(cls, config, section): """Creates a JobDescriptor from a ConfigParser section""" if section.startswith(JOB_PREFIX): - jobname = section[len(JOB_PREFIX) :] + jobname = section.removeprefix(JOB_PREFIX) else: raise InvalidJobSectionName(section) diff --git a/python/nav/ipdevpoll/log.py b/python/nav/ipdevpoll/log.py index 91d0a76c4a..7cca2cce5a 100644 --- a/python/nav/ipdevpoll/log.py +++ b/python/nav/ipdevpoll/log.py @@ -45,7 +45,7 @@ def __init__(self, pidlog=False): def format(self, record): """Overridden to choose format based on record contents.""" self._set_context(record) - self._strip_logger_prefix(record) + record.name = record.name.removeprefix(self.prefix) return Formatter.format(self, record) def _set_context(self, record): @@ -64,10 +64,6 @@ def _set_format(self, fmt): self._fmt = fmt self._style._fmt = fmt - def _strip_logger_prefix(self, record): - if record.name.startswith(self.prefix): - record.name = record.name[len(self.prefix) :] - # pylint: disable=R0903 class ContextLogger(object): diff --git a/python/nav/ipdevpoll/plugins/dot1q.py b/python/nav/ipdevpoll/plugins/dot1q.py index 1391303b2c..fe07d2e703 100644 --- a/python/nav/ipdevpoll/plugins/dot1q.py +++ b/python/nav/ipdevpoll/plugins/dot1q.py @@ -172,8 +172,7 @@ def _get_vlan_names(self): for vlannum, name in names.items(): vlannum = self._remap_vlan(vlannum) suffix = '+{}'.format(vlannum) - if name.endswith(suffix): - name = name[: -len(suffix)] + name = name.removesuffix(suffix) vlan = self.containers.factory(name, shadows.Vlan) vlan.net_type = shadows.NetType.get('lan') vlan.vlan = vlannum diff --git a/python/nav/ipdevpoll/plugins/prefix.py b/python/nav/ipdevpoll/plugins/prefix.py index b26b665775..2f8d88a629 100644 --- a/python/nav/ipdevpoll/plugins/prefix.py +++ b/python/nav/ipdevpoll/plugins/prefix.py @@ -264,7 +264,7 @@ def __init__(self, string): for oper in self.OPERATORS: if string.startswith(oper): self.match_operator = oper - string = string[len(oper) :] + string = string.removeprefix(oper) break IP.__init__(self, string) # stupid old-style class implementation! diff --git a/python/nav/models/fields.py b/python/nav/models/fields.py index 6efc77f7b2..6fd5a54803 100644 --- a/python/nav/models/fields.py +++ b/python/nav/models/fields.py @@ -128,14 +128,10 @@ def from_db_value(self, value, expression, connection): def to_python(self, value): if not value or isinstance(value, tuple): return value - if isinstance(value, str): - if validators.is_valid_point_string(value): - if value.startswith('(') and value.endswith(')'): - noparens = value[1:-1] - else: - noparens = value - latitude, longitude = noparens.split(',') - return (Decimal(latitude.strip()), Decimal(longitude.strip())) + if isinstance(value, str) and validators.is_valid_point_string(value): + noparens = value.removeprefix("(").removesuffix(")") + latitude, longitude = noparens.split(',') + return (Decimal(latitude.strip()), Decimal(longitude.strip())) raise exceptions.ValidationError("This value must be a point-string.") def get_db_prep_value(self, value, connection, prepared=False): diff --git a/python/nav/models/manage.py b/python/nav/models/manage.py index 2d5c3492ce..896a2c2242 100644 --- a/python/nav/models/manage.py +++ b/python/nav/models/manage.py @@ -509,12 +509,9 @@ def get_short_sysname(self): """Returns sysname without the domain suffix if specified in the DOMAIN_SUFFIX setting in nav.conf""" - if settings.DOMAIN_SUFFIX is not None and self.sysname.endswith( - settings.DOMAIN_SUFFIX - ): - return self.sysname[: -len(settings.DOMAIN_SUFFIX)] - else: - return self.sysname or self.ip + if settings.DOMAIN_SUFFIX is not None: + return self.sysname.removesuffix(settings.DOMAIN_SUFFIX) + return self.sysname or self.ip def is_on_maintenance(self): """Returns True if this netbox is currently on maintenance""" diff --git a/python/nav/models/profiles.py b/python/nav/models/profiles.py index c5d97f0203..8fea91f85e 100644 --- a/python/nav/models/profiles.py +++ b/python/nav/models/profiles.py @@ -282,9 +282,9 @@ def locked(self): @locked.setter def locked(self, value): - if not value and self.password.startswith('!'): - self.password = self.password[1:] - elif value and not self.password.startswith('!'): + if not value: + self.password = self.password.removeprefix("!") + elif not self.password.startswith('!'): self.password = '!' + self.password @property diff --git a/python/nav/startstop.py b/python/nav/startstop.py index 16cfea6788..b8c3b808a4 100644 --- a/python/nav/startstop.py +++ b/python/nav/startstop.py @@ -43,7 +43,7 @@ def get_info_from_content(content): if not line.startswith('#'): break elif line.startswith(INFOHEAD): - return line[len(INFOHEAD) :].strip() + return line.removeprefix(INFOHEAD).strip() class Service(object): diff --git a/python/nav/statemon/abstractchecker.py b/python/nav/statemon/abstractchecker.py index dff8e6681b..f998087308 100644 --- a/python/nav/statemon/abstractchecker.py +++ b/python/nav/statemon/abstractchecker.py @@ -230,8 +230,7 @@ def get_type(cls): """Returns the name of the handler.""" suffix = "checker" name = cls.__name__.lower() - if name.endswith(suffix): - name = name[: -len(suffix)] + name = name.removesuffix(suffix) return name def get_address(self): diff --git a/python/nav/statemon/checker/FtpChecker.py b/python/nav/statemon/checker/FtpChecker.py index dd8d50f494..d18c815ce5 100644 --- a/python/nav/statemon/checker/FtpChecker.py +++ b/python/nav/statemon/checker/FtpChecker.py @@ -51,7 +51,7 @@ def execute(self): version = '' for line in welcome.split('\n'): if line.startswith('220 '): - version = line[4:].strip() + version = line.removeprefix('220 ').strip() self.version = version username = self.args.get('username', '') diff --git a/python/nav/statemon/checker/MysqlChecker.py b/python/nav/statemon/checker/MysqlChecker.py index 525ecdd781..64c0e9926b 100644 --- a/python/nav/statemon/checker/MysqlChecker.py +++ b/python/nav/statemon/checker/MysqlChecker.py @@ -92,7 +92,7 @@ def read_packet(self): data = self.file.read(size) if data.startswith(b'\xff'): - error = data[3:].decode("utf-8") + error = data.removeprefix(b'\xff').decode("utf-8") raise MysqlError(error) return data diff --git a/python/nav/statemon/checkermap.py b/python/nav/statemon/checkermap.py index dbe607c42a..5fec492a68 100644 --- a/python/nav/statemon/checkermap.py +++ b/python/nav/statemon/checkermap.py @@ -63,6 +63,6 @@ def parsedir(): fnames = os.listdir(CHECKER_DIR) for fname in fnames: if fname.endswith(HANDLER_PATTERN): - key = fname[: -len(HANDLER_PATTERN)].lower() + key = fname.removesuffix(HANDLER_PATTERN).lower() handler = fname[:-3] register(key, handler) diff --git a/python/nav/web/geomap/db.py b/python/nav/web/geomap/db.py index 99889821d2..2651315620 100644 --- a/python/nav/web/geomap/db.py +++ b/python/nav/web/geomap/db.py @@ -367,9 +367,8 @@ def get_data(db_cursor, bounds, time_interval=None): for netbox in netboxes: netbox['load'] = float('nan') netbox['real_sysname'] = netbox['sysname'] - if _domain_suffix and netbox['sysname'].endswith(_domain_suffix): - hostname_length = len(netbox['sysname']) - len(_domain_suffix) - netbox['sysname'] = netbox['sysname'][0:hostname_length] + if _domain_suffix: + netbox['sysname'] = netbox['sysname'].removesuffix(_domain_suffix) return netboxes, connections diff --git a/tests/integration/models/model_test.py b/tests/integration/models/model_test.py index e36e0a5a3f..2e356957f4 100644 --- a/tests/integration/models/model_test.py +++ b/tests/integration/models/model_test.py @@ -4,6 +4,7 @@ Intended purpose is to catch obvious omissions in DB state or the Django models themselves. """ + import os from django.db import connection @@ -21,7 +22,7 @@ # Ensure that all modules are loaded for file_name in os.listdir(os.path.dirname(nav.models.__file__)): if file_name.endswith('.py') and not file_name.startswith('__init__'): - module_name = file_name.replace('.py', '') + module_name = file_name.removesuffix('.py') __import__('nav.models.%s' % module_name)