From 62ef10620f5fd16614f43165c0e5eb97b684af79 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 3 May 2021 17:24:04 -0400 Subject: [PATCH] re-format with black --- daemon/__init__.py | 4 +- daemon/_metadata.py | 41 +-- daemon/daemon.py | 122 +++---- daemon/pidfile.py | 6 +- daemon/runner.py | 54 ++-- hbdclass.py | 628 ++++++++++++++++++------------------ lockfile/__init__.py | 70 ++-- lockfile/linklockfile.py | 20 +- lockfile/mkdirlockfile.py | 23 +- lockfile/pidlockfile.py | 20 +- lockfile/sqlitelockfile.py | 86 ++--- lockfile/symlinklockfile.py | 18 +- 12 files changed, 564 insertions(+), 528 deletions(-) diff --git a/daemon/__init__.py b/daemon/__init__.py index 4731a6e..9d10dda 100644 --- a/daemon/__init__.py +++ b/daemon/__init__.py @@ -37,11 +37,11 @@ """ -from __future__ import (absolute_import, unicode_literals) +from __future__ import absolute_import, unicode_literals from .daemon import DaemonContext - + # Local variables: # coding: utf-8 # mode: python diff --git a/daemon/_metadata.py b/daemon/_metadata.py index 6d22a2b..32b26fd 100644 --- a/daemon/_metadata.py +++ b/daemon/_metadata.py @@ -12,7 +12,7 @@ """ Package metadata for the ‘python-daemon’ distribution. """ -from __future__ import (absolute_import, unicode_literals) +from __future__ import absolute_import, unicode_literals import json import re @@ -21,10 +21,11 @@ import datetime import pkg_resources - + distribution_name = "python-daemon" version_info_filename = "version_info.json" + def get_distribution_version_info(filename=version_info_filename): """ Get the version info from the installed distribution. @@ -37,10 +38,10 @@ def get_distribution_version_info(filename=version_info_filename): """ version_info = { - 'release_date': "UNKNOWN", - 'version': "UNKNOWN", - 'maintainer': "UNKNOWN", - } + "release_date": "UNKNOWN", + "version": "UNKNOWN", + "maintainer": "UNKNOWN", + } try: distribution = pkg_resources.get_distribution(distribution_name) @@ -54,15 +55,16 @@ def get_distribution_version_info(filename=version_info_filename): return version_info + version_info = get_distribution_version_info() -version_installed = version_info['version'] +version_installed = version_info["version"] - -rfc822_person_regex = re.compile( - "^(?P[^<]+) <(?P[^>]+)>$") -ParsedPerson = collections.namedtuple('ParsedPerson', ['name', 'email']) +rfc822_person_regex = re.compile("^(?P[^<]+) <(?P[^>]+)>$") + +ParsedPerson = collections.namedtuple("ParsedPerson", ["name", "email"]) + def parse_person_field(value): """ Parse a person field into name and email address. @@ -79,19 +81,18 @@ def parse_person_field(value): match = rfc822_person_regex.match(value) if len(value): if match is not None: - result = ParsedPerson( - name=match.group('name'), - email=match.group('email')) + result = ParsedPerson(name=match.group("name"), email=match.group("email")) else: result = ParsedPerson(name=value, email=None) - return result + return result + author_name = "Ben Finney" author_email = "ben+python@benfinney.id.au" author = "{name} <{email}>".format(name=author_name, email=author_email) - + class YearRange: """ A range of years spanning a period. """ @@ -135,16 +136,18 @@ def make_year_range(begin_year, end_date=None): return year_range + copyright_year_begin = "2001" -build_date = version_info['release_date'] +build_date = version_info["release_date"] copyright_year_range = make_year_range(copyright_year_begin, build_date) copyright = "Copyright © {year_range} {author} and others".format( - year_range=copyright_year_range, author=author) + year_range=copyright_year_range, author=author +) license = "Apache-2" url = "https://alioth.debian.org/projects/python-daemon/" - + # Local variables: # coding: utf-8 # mode: python diff --git a/daemon/daemon.py b/daemon/daemon.py index 06b95ab..d997c1b 100644 --- a/daemon/daemon.py +++ b/daemon/daemon.py @@ -18,7 +18,7 @@ """ Daemon process behaviour. """ -from __future__ import (absolute_import, unicode_literals) +from __future__ import absolute_import, unicode_literals import os import sys @@ -27,6 +27,7 @@ import errno import signal import socket import atexit + try: # Python 2 has both ‘str’ (bytes) and ‘unicode’ (text). basestring = basestring @@ -36,7 +37,7 @@ except NameError: basestring = str unicode = str - + class DaemonError(Exception): """ Base exception class for errors from this module. """ @@ -56,7 +57,7 @@ class DaemonOSEnvironmentError(DaemonError, OSError): class DaemonProcessDetachError(DaemonError, OSError): """ Exception raised when process detach fails. """ - + class DaemonContext: """ Context for turning the current program into a daemon process. @@ -231,21 +232,21 @@ class DaemonContext: __metaclass__ = type def __init__( - self, - chroot_directory=None, - working_directory="/", - umask=0, - uid=None, - gid=None, - prevent_core=True, - detach_process=None, - files_preserve=None, - pidfile=None, - stdin=None, - stdout=None, - stderr=None, - signal_map=None, - ): + self, + chroot_directory=None, + working_directory="/", + umask=0, + uid=None, + gid=None, + prevent_core=True, + detach_process=None, + files_preserve=None, + pidfile=None, + stdin=None, + stdout=None, + stderr=None, + signal_map=None, + ): """ Set up a new instance. """ self.chroot_directory = chroot_directory self.working_directory = working_directory @@ -427,8 +428,10 @@ class DaemonContext: """ exception = SystemExit( - "Terminating on signal {signal_number!r}".format( - signal_number=signal_number)) + "Terminating on signal {signal_number!r}".format( + signal_number=signal_number + ) + ) raise exception def _get_exclude_file_descriptors(self): @@ -454,8 +457,10 @@ class DaemonContext: if files_preserve is None: files_preserve = [] files_preserve.extend( - item for item in [self.stdin, self.stdout, self.stderr] - if hasattr(item, 'fileno')) + item + for item in [self.stdin, self.stdout, self.stderr] + if hasattr(item, "fileno") + ) exclude_descriptors = set() for item in files_preserve: @@ -502,8 +507,9 @@ class DaemonContext: """ signal_handler_map = dict( - (signal_number, self._make_signal_handler(target)) - for (signal_number, target) in self.signal_map.items()) + (signal_number, self._make_signal_handler(target)) + for (signal_number, target) in self.signal_map.items() + ) return signal_handler_map @@ -520,7 +526,7 @@ def _get_file_descriptor(obj): """ file_descriptor = None - if hasattr(obj, 'fileno'): + if hasattr(obj, "fileno"): try: file_descriptor = obj.fileno() except ValueError: @@ -529,7 +535,7 @@ def _get_file_descriptor(obj): return file_descriptor - + def change_working_directory(directory): """ Change the working directory of this process. @@ -541,7 +547,8 @@ def change_working_directory(directory): os.chdir(directory) except Exception as exc: error = DaemonOSEnvironmentError( - "Unable to change working directory ({exc})".format(exc=exc)) + "Unable to change working directory ({exc})".format(exc=exc) + ) raise error @@ -561,7 +568,8 @@ def change_root_directory(directory): os.chroot(directory) except Exception as exc: error = DaemonOSEnvironmentError( - "Unable to change root directory ({exc})".format(exc=exc)) + "Unable to change root directory ({exc})".format(exc=exc) + ) raise error @@ -576,7 +584,8 @@ def change_file_creation_mask(mask): os.umask(mask) except Exception as exc: error = DaemonOSEnvironmentError( - "Unable to change file creation mask ({exc})".format(exc=exc)) + "Unable to change file creation mask ({exc})".format(exc=exc) + ) raise error @@ -597,10 +606,11 @@ def change_process_owner(uid, gid): os.setuid(uid) except Exception as exc: error = DaemonOSEnvironmentError( - "Unable to change process owner ({exc})".format(exc=exc)) + "Unable to change process owner ({exc})".format(exc=exc) + ) raise error - + def prevent_core_dump(): """ Prevent this process from generating a core dump. @@ -618,15 +628,16 @@ def prevent_core_dump(): core_limit_prev = resource.getrlimit(core_resource) except ValueError as exc: error = DaemonOSEnvironmentError( - "System does not support RLIMIT_CORE resource limit" - " ({exc})".format(exc=exc)) + "System does not support RLIMIT_CORE resource limit" + " ({exc})".format(exc=exc) + ) raise error # Set hard and soft limits to zero, i.e. no core dump at all. core_limit = (0, 0) resource.setrlimit(core_resource, core_limit) - + def detach_process_context(): """ Detach the process context from parent and session. @@ -656,15 +667,17 @@ def detach_process_context(): os._exit(0) except OSError as exc: error = DaemonProcessDetachError( - "{message}: [{exc.errno:d}] {exc.strerror}".format( - message=error_message, exc=exc)) + "{message}: [{exc.errno:d}] {exc.strerror}".format( + message=error_message, exc=exc + ) + ) raise error fork_then_exit_parent(error_message="Failed first fork") os.setsid() fork_then_exit_parent(error_message="Failed second fork") - + def is_process_started_by_init(): """ Determine whether the current process is started by `init`. @@ -699,8 +712,7 @@ def is_socket(fd): file_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_RAW) try: - socket_type = file_socket.getsockopt( - socket.SOL_SOCKET, socket.SO_TYPE) + socket_type = file_socket.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE) except socket.error as exc: exc_errno = exc.args[0] if exc_errno == errno.ENOTSOCK: @@ -759,7 +771,7 @@ def is_detach_process_context_required(): return result - + def close_file_descriptor_if_open(fd): """ Close a file descriptor if already open. @@ -778,13 +790,14 @@ def close_file_descriptor_if_open(fd): pass else: error = DaemonOSEnvironmentError( - "Failed to close file descriptor {fd:d} ({exc})".format( - fd=fd, exc=exc)) + "Failed to close file descriptor {fd:d} ({exc})".format(fd=fd, exc=exc) + ) raise error MAXFD = 2048 + def get_maximum_file_descriptors(): """ Get the maximum number of open file descriptors for this process. @@ -820,7 +833,7 @@ def close_all_open_files(exclude=set()): if fd not in exclude: close_file_descriptor_if_open(fd) - + def redirect_stream(system_stream, target_stream): """ Redirect a system stream to a specified file. @@ -844,7 +857,7 @@ def redirect_stream(system_stream, target_stream): target_fd = target_stream.fileno() os.dup2(target_fd, system_stream.fileno()) - + def make_default_signal_map(): """ Make the default signal map for this system. @@ -855,15 +868,16 @@ def make_default_signal_map(): """ name_map = { - 'SIGTSTP': None, - 'SIGTTIN': None, - 'SIGTTOU': None, - 'SIGTERM': 'terminate', - } + "SIGTSTP": None, + "SIGTTIN": None, + "SIGTTOU": None, + "SIGTERM": "terminate", + } signal_map = dict( - (getattr(signal, name), target) - for (name, target) in name_map.items() - if hasattr(signal, name)) + (getattr(signal, name), target) + for (name, target) in name_map.items() + if hasattr(signal, name) + ) return signal_map @@ -895,7 +909,7 @@ def register_atexit_function(func): """ atexit.register(func) - + def _chain_exception_from_existing_exception_context(exc, as_cause=False): """ Decorate the specified exception with the existing exception context. @@ -918,7 +932,7 @@ def _chain_exception_from_existing_exception_context(exc, as_cause=False): exc.__context__ = existing_exc exc.__traceback__ = existing_traceback - + # Local variables: # coding: utf-8 # mode: python diff --git a/daemon/pidfile.py b/daemon/pidfile.py index 4517ee0..781bea9 100644 --- a/daemon/pidfile.py +++ b/daemon/pidfile.py @@ -13,11 +13,11 @@ """ Lockfile behaviour implemented via Unix PID files. """ -from __future__ import (absolute_import, unicode_literals) +from __future__ import absolute_import, unicode_literals from lockfile.pidlockfile import PIDLockFile - + class TimeoutPIDLockFile(PIDLockFile, object): """ Lockfile with default timeout, implemented as a Unix PID file. @@ -59,7 +59,7 @@ class TimeoutPIDLockFile(PIDLockFile, object): timeout = self.acquire_timeout super(TimeoutPIDLockFile, self).acquire(timeout, *args, **kwargs) - + # Local variables: # coding: utf-8 # mode: python diff --git a/daemon/runner.py b/daemon/runner.py index 6973cf1..0733b52 100644 --- a/daemon/runner.py +++ b/daemon/runner.py @@ -17,12 +17,13 @@ """ Daemon runner library. """ -from __future__ import (absolute_import, unicode_literals) +from __future__ import absolute_import, unicode_literals import sys import os import signal import errno + try: # Python 3 standard library. ProcessLookupError @@ -33,11 +34,11 @@ except NameError: import lockfile from . import pidfile -from .daemon import (basestring, unicode) +from .daemon import basestring, unicode from .daemon import DaemonContext from .daemon import _chain_exception_from_existing_exception_context - + class DaemonRunnerError(Exception): """ Abstract base class for errors from DaemonRunner. """ @@ -65,7 +66,7 @@ class DaemonRunnerStartFailureError(DaemonRunnerError, RuntimeError): class DaemonRunnerStopFailureError(DaemonRunnerError, RuntimeError): """ Raised when failure stopping DaemonRunner. """ - + class DaemonRunner: """ Controller for a callable running in a separate background process. @@ -107,15 +108,13 @@ class DaemonRunner: self.parse_args() self.app = app self.daemon_context = DaemonContext() - self.daemon_context.stdin = open(app.stdin_path, 'rt') - self.daemon_context.stdout = open(app.stdout_path, 'w+t') - self.daemon_context.stderr = open( - app.stderr_path, 'w+t', buffering=0) + self.daemon_context.stdin = open(app.stdin_path, "rt") + self.daemon_context.stdout = open(app.stdout_path, "w+t") + self.daemon_context.stderr = open(app.stderr_path, "w+t", buffering=0) self.pidfile = None if app.pidfile_path is not None: - self.pidfile = make_pidlockfile( - app.pidfile_path, app.pidfile_timeout) + self.pidfile = make_pidlockfile(app.pidfile_path, app.pidfile_timeout) self.daemon_context.pidfile = self.pidfile def _usage_exit(self, argv): @@ -130,7 +129,8 @@ class DaemonRunner: usage_exit_code = 2 action_usage = "|".join(self.action_funcs.keys()) message = "usage: {progname} {usage}".format( - progname=progname, usage=action_usage) + progname=progname, usage=action_usage + ) emit_message(message) sys.exit(usage_exit_code) @@ -175,8 +175,8 @@ class DaemonRunner: self.daemon_context.open() except lockfile.AlreadyLocked: error = DaemonRunnerStartFailureError( - "PID file {pidfile.path!r} already locked".format( - pidfile=self.pidfile)) + "PID file {pidfile.path!r} already locked".format(pidfile=self.pidfile) + ) raise error pid = os.getpid() @@ -198,8 +198,8 @@ class DaemonRunner: os.kill(pid, signal.SIGTERM) except OSError as exc: error = DaemonRunnerStopFailureError( - "Failed to terminate {pid:d}: {exc}".format( - pid=pid, exc=exc)) + "Failed to terminate {pid:d}: {exc}".format(pid=pid, exc=exc) + ) raise error def _stop(self): @@ -212,8 +212,8 @@ class DaemonRunner: """ if not self.pidfile.is_locked(): error = DaemonRunnerStopFailureError( - "PID file {pidfile.path!r} not locked".format( - pidfile=self.pidfile)) + "PID file {pidfile.path!r} not locked".format(pidfile=self.pidfile) + ) raise error if is_pidfile_stale(self.pidfile): @@ -228,10 +228,10 @@ class DaemonRunner: self._start() action_funcs = { - 'start': _start, - 'stop': _stop, - 'restart': _restart, - } + "start": _start, + "stop": _stop, + "restart": _restart, + } def _get_action_func(self): """ Get the function for the specified action. @@ -249,8 +249,8 @@ class DaemonRunner: func = self.action_funcs[self.action] except KeyError: error = DaemonRunnerInvalidActionError( - "Unknown action: {action!r}".format( - action=self.action)) + "Unknown action: {action!r}".format(action=self.action) + ) raise error return func @@ -278,12 +278,10 @@ def emit_message(message, stream=None): def make_pidlockfile(path, acquire_timeout): """ Make a PIDLockFile instance with the given filesystem path. """ if not isinstance(path, basestring): - error = ValueError("Not a filesystem path: {path!r}".format( - path=path)) + error = ValueError("Not a filesystem path: {path!r}".format(path=path)) raise error if not os.path.isabs(path): - error = ValueError("Not an absolute path: {path!r}".format( - path=path)) + error = ValueError("Not an absolute path: {path!r}".format(path=path)) raise error lockfile = pidfile.TimeoutPIDLockFile(path, acquire_timeout) @@ -316,7 +314,7 @@ def is_pidfile_stale(pidfile): return result - + # Local variables: # coding: utf-8 # mode: python diff --git a/hbdclass.py b/hbdclass.py index 3b74502..93d392b 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -1,4 +1,3 @@ - """ host and connection class shared between hbd and the websit's heartbeat.py @@ -13,358 +12,349 @@ num = 0 MAXRTTS = 10 -DEBUG=2 +DEBUG = 2 + def log(host, m): - if DEBUG: - print("class log: %s %s" % (host, m)) + if DEBUG: + print("class log: %s %s" % (host, m)) class Connection: - # map of addrs to names - - htab = {} - unknown = "unknown" - up = "up" - down = "down" - overdue = "overdue" + # map of addrs to names - def __init__(self, host, cid, addr, afam): - self.host = host - self.cid = cid - self.addr = addr - self.afam = afam - self.rtts = [0] - self.lastbeat = time.time() - self.statetime = self.lastbeat - self.deltastatetime = 'computed' - self.state = Connection.unknown + htab = {} + unknown = "unknown" + up = "up" + down = "down" + overdue = "overdue" - if host: - r = "new addr %s" % (addr) - Connection.htab[addr] = self.host.name - if self.host.isDynDns(): - log(self.host.name, "dns update %s" % self.addr) - Host.dnsQ.put((self.host.name, self.addr)) + def __init__(self, host, cid, addr, afam): + self.host = host + self.cid = cid + self.addr = addr + self.afam = afam + self.rtts = [0] + self.lastbeat = time.time() + self.statetime = self.lastbeat + self.deltastatetime = "computed" + self.state = Connection.unknown - def registerDns(self): - Host.dnsQ.put((self.host.name, self.addr)) + if host: + r = "new addr %s" % (addr) + Connection.htab[addr] = self.host.name + if self.host.isDynDns(): + log(self.host.name, "dns update %s" % self.addr) + Host.dnsQ.put((self.host.name, self.addr)) + + def registerDns(self): + Host.dnsQ.put((self.host.name, self.addr)) + + def statedict(self, Null=False): + d = {} + now = time.time() + if not Null: + d["addr"] = self.addr + if self.rtts[-1]: + d["rtt"] = "%0.1f" % self.rtts[-1] + elif self.state == Connection.unknown: + d["rtt"] = "" + else: + d["rtt"] = "?" + d["lastbeat"] = self.lastbeat + if self.state == Connection.overdue: + d["state"] = "%s" % self.state + else: + d["state"] = self.state + if self.state == Connection.up: + d["rttstate"] = d["rtt"] + elif self.state == Connection.overdue: + d["rttstate"] = "" + else: + d["rttstate"] = d["state"] + d["statetime"] = time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(self.statetime) + ) + delta = now - self.statetime + + if self.state == Connection.unknown: + d["deltastatetime"] = "" + elif delta > 86400: + # d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) + d["deltastatetime"] = "%0.1f days" % (delta / 86400.0) + elif delta > 3600: + # d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta)) + d["deltastatetime"] = time.strftime("%k:%M hrs", time.gmtime(delta)) + # d['deltastatetime'] = "%0.1f hrs" % (delta / 3600.) + elif delta > 60: + # d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta)) + d["deltastatetime"] = time.strftime("%M:%S mins", time.gmtime(delta)) + # d['deltastatetime'] = "%0.1f mins" % (delta / 60.) + else: + # d['deltastatetime'] = time.strftime("%S", time.gmtime(delta)) + d["deltastatetime"] = "%i secs" % (delta) + + else: + d["addr"] = "" + d["rtt"] = "" + d["lastbeat"] = "" + d["state"] = "" + d["statetime"] = "" + d["deltastatetime"] = "" + d["rttstate"] = "" + return d + + def headerdict(self, afam): + d = {} + d["addr"] = "%s Addr" % afam + d["rtt"] = "Latencey" + d["lastbeat"] = "Last Contact" + d["state"] = "State" + d["statetime"] = "Last State" + d["rttstate"] = "Reach" + d["deltastatetime"] = "Last State" + return d + + def jsons(self): + return json.dumps(self.__dict__) + + # set new state, return number of secs in previous state + def newstate(self, state, now, when=0): + self.state = state + delta = now - when + s = delta - self.statetime + self.statetime = delta + return s + + def getstate(self): + return self.state + + def newaddr(self, addr, rtt, now): + self.lastbeat = now + self.rtts.append(rtt) + if len(self.rtts) > MAXRTTS: + del self.rtts[0] + + if self.addr == addr: + r = None + else: + r = "changed from %s to %s" % (self.addr, addr) + try: + del Connection.htab[self.addr] + except: + pass + self.addr = addr + Connection.htab[addr] = self.host.name + if self.host.isDynDns(): + Host.dnsQ.put((self.host.name, self.addr)) + return r - def statedict(self, Null=False): - d = {} - now = time.time() - if not Null: - d['addr'] = self.addr - if self.rtts[-1]: - d['rtt'] = "%0.1f" % self.rtts[-1] - elif self.state == Connection.unknown: - d['rtt'] = "" - else: - d['rtt'] = "?" - d['lastbeat'] = self.lastbeat - if self.state == Connection.overdue: - d['state'] = "%s" % self.state - else: - d['state'] = self.state - if self.state == Connection.up: - d['rttstate'] = d['rtt'] - elif self.state == Connection.overdue: - d['rttstate'] = '' - else: - d['rttstate'] = d['state'] - d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime)) - delta = now - self.statetime - - if self.state == Connection.unknown: - d['deltastatetime'] = '' - elif delta > 86400: -# d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) - d['deltastatetime'] = "%0.1f days" % (delta / 86400.) - elif delta > 3600: -# d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta)) - d['deltastatetime'] = time.strftime("%k:%M hrs", time.gmtime(delta)) -# d['deltastatetime'] = "%0.1f hrs" % (delta / 3600.) - elif delta > 60: -# d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta)) - d['deltastatetime'] = time.strftime("%M:%S mins", time.gmtime(delta)) -# d['deltastatetime'] = "%0.1f mins" % (delta / 60.) - else: -# d['deltastatetime'] = time.strftime("%S", time.gmtime(delta)) - d['deltastatetime'] = "%i secs" % (delta) - - else: - d['addr'] = '' - d['rtt'] = "" - d['lastbeat'] = '' - d['state'] = '' - d['statetime'] = '' - d['deltastatetime'] = '' - d['rttstate'] = '' - return d - - - def headerdict(self, afam): - d = {} - d['addr'] = '%s Addr' % afam - d['rtt'] = 'Latencey' - d['lastbeat'] = 'Last Contact' - d['state'] = 'State' - d['statetime'] = 'Last State' - d['rttstate'] = 'Reach' - d['deltastatetime'] = 'Last State' - return d - - - def jsons(self): - return(json.dumps(self.__dict__)) - - - # set new state, return number of secs in previous state - def newstate(self, state, now, when=0): - self.state = state - delta = now - when - s = delta - self.statetime - self.statetime = delta - return s - - - def getstate(self): - return self.state - - - def newaddr(self, addr, rtt, now): - self.lastbeat = now - self.rtts.append(rtt) - if len(self.rtts) > MAXRTTS: - del self.rtts[0] - - if self.addr == addr: - r = None - else: - r = "changed from %s to %s" % (self.addr, addr) - try: - del Connection.htab[self.addr] - except: - pass - self.addr = addr - Connection.htab[addr] = self.host.name - if self.host.isDynDns(): - Host.dnsQ.put((self.host.name, self.addr)) - return r - - -# +# class Host: - # Table of Hosts - hosts = {} + # Table of Hosts + hosts = {} - def __init__(self, name): - global num - self.name = name - if name: - num += 1 - Host.hosts[name] = self - self.num = num - self.dyn = False - self.watched = False - self.upcount = 0 - self.interval = 0 - self.doesack = -1 - self.cmds = [] - self.cver = 0 - self.connections = {} - self.hdwcounts = [[0,0],[0,0],[0,0]] + def __init__(self, name): + global num + self.name = name + if name: + num += 1 + Host.hosts[name] = self + self.num = num + self.dyn = False + self.watched = False + self.upcount = 0 + self.interval = 0 + self.doesack = -1 + self.cmds = [] + self.cver = 0 + self.connections = {} + self.hdwcounts = [[0, 0], [0, 0], [0, 0]] + def statedict(self): + d = {} + d["name"] = self.name + if self.dyn: + d["name"] += "*" + if self.watched: + d["name"] = "%s" % d["name"] + d["dyn"] = str(self.dyn) + d["ver"] = str(self.cver) + d["num"] = self.num + for c in ["IPv4", "IPv6"]: + if c in self.connections: + cs = self.connections[c].statedict() + else: + cs = ubConnection.statedict(True) + for csv in cs: + d["%s.%s" % (c, csv)] = cs[csv] - def statedict(self): - d = {} - d['name'] = self.name - if self.dyn: - d['name'] += "*" - if self.watched: - d['name'] = "%s" % d['name'] - d['dyn'] = str(self.dyn) - d['ver'] = str(self.cver) - d['num'] = self.num - for c in ['IPv4', 'IPv6']: - if c in self.connections: - cs = self.connections[c].statedict() - else: - cs = ubConnection.statedict(True) - for csv in cs: - d['%s.%s' % (c, csv) ] = cs[csv] + return d - return d + def headerdict(self): + d = {} + d["name"] = "Name" + d["dyn"] = "Dyn" + d["ver"] = "Ver" + d["num"] = "??" + for c in ["IPv4", "IPv6"]: + cs = ubConnection.headerdict(c) + for csv in cs: + d["%s.%s" % (c, csv)] = cs[csv] + return d + def registerDns(self): + for af in self.connections: + self.connections[af].registerDns() - def headerdict(self): - d = {} - d['name'] = 'Name' - d['dyn'] = 'Dyn' - d['ver'] = 'Ver' - d['num'] = '??' - for c in ['IPv4', 'IPv6']: - cs = ubConnection.headerdict(c) - for csv in cs: - d['%s.%s' % (c, csv) ] = cs[csv] - return d + def jsons(self): + ddict = {} + for d in self.__dict__: + if d == "connections": + cl = [] + for c in self.connections: + # dirty ugly hack: fix conn to host backpointer + cld = copy.deepcopy(self.connections[c].__dict__) + cld["host"] = cld["host"].name + cl.append(cld) + ddict[d] = cl + else: + ddict[d] = self.__dict__[d] + return json.dumps(ddict) + def setcver(self, cver): + self.cver = cver - def registerDns(self): - for af in self.connections: - self.connections[af].registerDns() + def isDynDns(self): + return self.dyn + def isIPv4(self, addr): + if type(addr) == type(()): + return addr[0].find(".") > 0 + else: + return addr.find(".") > 0 - def jsons(self): - ddict = {} - for d in self.__dict__: - if d == 'connections': - cl = [] - for c in self.connections: - # dirty ugly hack: fix conn to host backpointer - cld = copy.deepcopy(self.connections[c].__dict__) - cld['host'] = cld['host'].name - cl.append(cld) - ddict[d] = cl - else: - ddict[d] = self.__dict__[d] - return json.dumps(ddict) + def conndata(self, cid, addr, rtt, now): + if self.isIPv4(addr): + afam = "IPv4" + else: + afam = "IPv6" + if afam not in self.connections: + self.connections[afam] = Connection(self, cid, addr, afam) - def setcver(self, cver): - self.cver = cver + conn = self.connections[afam] + res = conn.newaddr(addr, rtt, now) + return conn, res + # called when reloading class from pickle, add new fields here + def fixup(self): + pass - def isDynDns(self): - return self.dyn + def dispstate(self): + if self.state in ["down", "overdue"]: + state = "%s" % self.state + elif self.state in ["up", "UP"]: + state = "" + for x in list(self.connections.keys()): + try: + state += " %5.1f" % (self.connections[x].rtts[-1]) + except: + state += " %5s" % (self.connections[x].rtts[-1]) + elif self.state in ["unknown", "UNKNOWN"]: + state = "" + else: + state = "%s" % self.state + return state + def dispstats(self): + if self.doesack != -1: + if self.upcount > 0: + # return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts) + r = "" + for v in range(3): + a, u = self.hdwcounts[v] + if (self.upcount - u) != 0: + vs = "%0.0f" % ( + 100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)) + ) + if vs == "0": + vs = "" + else: + vs = "-" + r += '%s' % vs + return r + else: + return "(%s)" % (self.doesack) + return 'N/A>' - def isIPv4(self, addr): - if type(addr) == type(()): - return addr[0].find('.') > 0 - else: - return addr.find('.') > 0 + hostfields_long = [ + "name", + "IPv4.addr", + "IPv4.state", + ("IPv4.rtt", 'style="text-align: right;"'), + ("IPv4.statetime", 'style="text-align: right;"'), + "IPv6.addr", + "IPv6.state", + ("IPv6.rtt", 'style="text-align: right;"'), + ("IPv6.statetime", 'style="text-align: right;"'), + "ver", + ] + hostfields_short = [ + "name", + ("IPv4.rttstate", 'style="text-align: right;"'), + ("IPv4.deltastatetime", 'style="text-align: right;"'), + ("IPv6.rttstate", 'style="text-align: right;"'), + ("IPv6.deltastatetime", 'style="text-align: right;"'), + ] - def conndata(self, cid, addr, rtt, now): - if self.isIPv4(addr): - afam = "IPv4" - else: - afam = "IPv6" + def gene(self, tag, v, attrib=None): + if attrib: + a = " %s" % attrib + else: + a = "" + return "<%s%s>%s" % (tag, a, v, tag) - if afam not in self.connections: - self.connections[afam] = Connection(self, cid, addr, afam) + def htmltable(self, tag, hd, short): + if short: + hostfields = Host.hostfields_short + else: + hostfields = Host.hostfields_long + h = [] + for f in hostfields: + if type(f) == type(()): + h.append(self.gene(tag, hd[f[0]], f[1])) + else: + h.append(self.gene(tag, hd[f])) + return self.gene("tr", "\n".join(h)) - conn = self.connections[afam] - res = conn.newaddr(addr, rtt, now) - return conn, res - - - # called when reloading class from pickle, add new fields here - def fixup(self): - pass - - - def dispstate(self): - if self.state in ["down", "overdue"]: - state = "%s" % self.state - elif self.state in ["up", "UP"]: - state = "" - for x in list(self.connections.keys()): - try: - state += " %5.1f" % (self.connections[x].rtts[-1]) - except: - state += " %5s" % (self.connections[x].rtts[-1]) - elif self.state in ["unknown", "UNKNOWN"]: - state = "" - else: - state = "%s" % self.state - return state - - - def dispstats(self): - if self.doesack != -1: - if self.upcount > 0: -# return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts) - r = "" - for v in range(3): - a,u = self.hdwcounts[v] - if (self.upcount - u) != 0: - vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u))) - if vs == "0": - vs="" - else: - vs="-" - r+= '%s' % vs - return r - else: - return "(%s)" % (self.doesack) - return 'N/A>' - - - hostfields_long = ['name', 'IPv4.addr', - 'IPv4.state', ('IPv4.rtt','style="text-align: right;"'), - ('IPv4.statetime','style="text-align: right;"'), 'IPv6.addr', - 'IPv6.state', ('IPv6.rtt', 'style="text-align: right;"'), - ('IPv6.statetime','style="text-align: right;"'), 'ver'] - - hostfields_short = ['name', - ('IPv4.rttstate','style="text-align: right;"'), - ('IPv4.deltastatetime','style="text-align: right;"'), - ('IPv6.rttstate','style="text-align: right;"'), - ('IPv6.deltastatetime','style="text-align: right;"')] - - def gene(self, tag, v, attrib=None): - if attrib: - a=" %s" % attrib - else: - a="" - return "<%s%s>%s" % (tag, a, v, tag) - - - def htmltable(self, tag, hd, short): - if short: - hostfields = Host.hostfields_short - else: - hostfields = Host.hostfields_long - h = [] - for f in hostfields: - if type(f) == type(()): - h.append(self.gene(tag, hd[f[0]], f[1])) - else: - h.append(self.gene(tag, hd[f])) - return self.gene("tr", "\n".join(h)) - - - def buildhosttable(self, short=False): - if DEBUG > 1: - print("DBG buildhosttable: start") - res = [] - res.append('') - res.append(ubHost.htmltable('th', ubHost.headerdict(), short)) - hosts_sorted = list(Host.hosts.keys()) - if len(hosts_sorted): - hosts_sorted.sort() - for h in hosts_sorted: - res.append(ubHost.htmltable('td', Host.hosts[h].statedict(), short)) - res.append("
") - if DEBUG > 1: - print("DBG buildhosttable: %s" % res) - return res - - - def buildmsgtable(self, msgs): - res = [] - le = max(40 - len(Host.hosts), 3) - res.append("

Log of Events

") - for m in msgs[len(msgs)-le:]: - res.append("%s
" % m) - return res + def buildhosttable(self, short=False): + if DEBUG > 1: + print("DBG buildhosttable: start") + res = [] + res.append('') + res.append(ubHost.htmltable("th", ubHost.headerdict(), short)) + hosts_sorted = list(Host.hosts.keys()) + if len(hosts_sorted): + hosts_sorted.sort() + for h in hosts_sorted: + res.append(ubHost.htmltable("td", Host.hosts[h].statedict(), short)) + res.append("
") + if DEBUG > 1: + print("DBG buildhosttable: %s" % res) + return res + def buildmsgtable(self, msgs): + res = [] + le = max(40 - len(Host.hosts), 3) + res.append("

Log of Events

") + for m in msgs[len(msgs) - le :]: + res.append("%s
" % m) + return res # create fake "unbound objects", remove in Python 3.0 ubHost = Host(None) ubConnection = Connection(None, "", "", "") - diff --git a/lockfile/__init__.py b/lockfile/__init__.py index a6f44a5..889933c 100644 --- a/lockfile/__init__.py +++ b/lockfile/__init__.py @@ -65,10 +65,21 @@ if not hasattr(threading, "current_thread"): if not hasattr(threading.Thread, "get_name"): threading.Thread.get_name = threading.Thread.getName -__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked', - 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock', - 'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock', - 'LockBase', 'locked'] +__all__ = [ + "Error", + "LockError", + "LockTimeout", + "AlreadyLocked", + "LockFailed", + "UnlockError", + "NotLocked", + "NotMyLock", + "LinkFileLock", + "MkdirFileLock", + "SQLiteFileLock", + "LockBase", + "locked", +] class Error(Exception): @@ -80,6 +91,7 @@ class Error(Exception): ... except Exception: ... pass """ + pass @@ -92,6 +104,7 @@ class LockError(Error): ... except Error: ... pass """ + pass @@ -103,6 +116,7 @@ class LockTimeout(LockError): ... except LockError: ... pass """ + pass @@ -114,6 +128,7 @@ class AlreadyLocked(LockError): ... except LockError: ... pass """ + pass @@ -125,6 +140,7 @@ class LockFailed(LockError): ... except LockError: ... pass """ + pass @@ -137,6 +153,7 @@ class UnlockError(Error): ... except Error: ... pass """ + pass @@ -148,6 +165,7 @@ class NotLocked(UnlockError): ... except UnlockError: ... pass """ + pass @@ -159,6 +177,7 @@ class NotMyLock(UnlockError): ... except UnlockError: ... pass """ + pass @@ -209,6 +228,7 @@ class _SharedBase(object): class LockBase(_SharedBase): """Base class for platform-specific lock classes.""" + def __init__(self, path, threaded=True, timeout=None): """ >>> lock = LockBase('somefile') @@ -223,7 +243,7 @@ class LockBase(_SharedBase): # Thread objects in Python 2.4 and earlier do not have ident # attrs. Worm around that. ident = getattr(t, "ident", hash(t)) - self.tname = "-%x" % (ident & 0xffffffff) + self.tname = "-%x" % (ident & 0xFFFFFFFF) else: self.tname = "" dirname = os.path.dirname(self.lock_file) @@ -235,11 +255,10 @@ class LockBase(_SharedBase): # and overwriting the already existing lock-file, then one # gets unlocked, deleting both lock-file and unique file, # finally the last lock errors out upon releasing. - self.unique_name = os.path.join(dirname, - "%s%s.%s%s" % (self.hostname, - self.tname, - self.pid, - hash(self.path))) + self.unique_name = os.path.join( + dirname, + "%s%s.%s%s" % (self.hostname, self.tname, self.pid, hash(self.path)), + ) self.timeout = timeout def is_locked(self): @@ -261,13 +280,15 @@ class LockBase(_SharedBase): raise NotImplemented("implement in subclass") def __repr__(self): - return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, - self.path) + return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, self.path) def _fl_helper(cls, mod, *args, **kwds): - warnings.warn("Import from %s module instead of lockfile package" % mod, - DeprecationWarning, stacklevel=2) + warnings.warn( + "Import from %s module instead of lockfile package" % mod, + DeprecationWarning, + stacklevel=2, + ) # This is a bit funky, but it's only for awhile. The way the unit tests # are constructed this function winds up as an unbound method, so it # actually takes three args, not two. We want to toss out self. @@ -286,8 +307,8 @@ def LinkFileLock(*args, **kwds): lockfile.linklockfile module. """ from . import linklockfile - return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", - *args, **kwds) + + return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", *args, **kwds) def MkdirFileLock(*args, **kwds): @@ -297,8 +318,10 @@ def MkdirFileLock(*args, **kwds): lockfile.mkdirlockfile module. """ from . import mkdirlockfile - return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", - *args, **kwds) + + return _fl_helper( + mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", *args, **kwds + ) def SQLiteFileLock(*args, **kwds): @@ -308,8 +331,10 @@ def SQLiteFileLock(*args, **kwds): lockfile.mkdirlockfile module. """ from . import sqlitelockfile - return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", - *args, **kwds) + + return _fl_helper( + sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", *args, **kwds + ) def locked(path, timeout=None): @@ -324,6 +349,7 @@ def locked(path, timeout=None): def myname(...): ... """ + def decor(func): @functools.wraps(func) def wrapper(*args, **kwargs): @@ -333,15 +359,19 @@ def locked(path, timeout=None): return func(*args, **kwargs) finally: lock.release() + return wrapper + return decor if hasattr(os, "link"): from . import linklockfile as _llf + LockFile = _llf.LinkLockFile else: from . import mkdirlockfile as _mlf + LockFile = _mlf.MkdirLockFile FileLock = LockFile diff --git a/lockfile/linklockfile.py b/lockfile/linklockfile.py index 2ca9be0..d48c514 100644 --- a/lockfile/linklockfile.py +++ b/lockfile/linklockfile.py @@ -3,8 +3,7 @@ from __future__ import absolute_import import time import os -from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, - AlreadyLocked) +from . import LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, AlreadyLocked class LinkLockFile(LockBase): @@ -41,12 +40,11 @@ class LinkLockFile(LockBase): if timeout is not None and time.time() > end_time: os.unlink(self.unique_name) if timeout > 0: - raise LockTimeout("Timeout waiting to acquire" - " lock for %s" % - self.path) + raise LockTimeout( + "Timeout waiting to acquire" " lock for %s" % self.path + ) else: - raise AlreadyLocked("%s is already locked" % - self.path) + raise AlreadyLocked("%s is already locked" % self.path) time.sleep(timeout is not None and timeout / 10 or 0.1) else: # Link creation succeeded. We're good to go. @@ -64,9 +62,11 @@ class LinkLockFile(LockBase): return os.path.exists(self.lock_file) def i_am_locking(self): - return (self.is_locked() and - os.path.exists(self.unique_name) and - os.stat(self.unique_name).st_nlink == 2) + return ( + self.is_locked() + and os.path.exists(self.unique_name) + and os.stat(self.unique_name).st_nlink == 2 + ) def break_lock(self): if os.path.exists(self.lock_file): diff --git a/lockfile/mkdirlockfile.py b/lockfile/mkdirlockfile.py index 05a8c96..b12eac1 100644 --- a/lockfile/mkdirlockfile.py +++ b/lockfile/mkdirlockfile.py @@ -5,12 +5,12 @@ import os import sys import errno -from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, - AlreadyLocked) +from . import LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, AlreadyLocked class MkdirLockFile(LockBase): """Lock file by creating a directory.""" + def __init__(self, path, threaded=True, timeout=None): """ >>> lock = MkdirLockFile('somefile') @@ -19,10 +19,9 @@ class MkdirLockFile(LockBase): LockBase.__init__(self, path, threaded, timeout) # Lock file itself is a directory. Place the unique file name into # it. - self.unique_name = os.path.join(self.lock_file, - "%s.%s%s" % (self.hostname, - self.tname, - self.pid)) + self.unique_name = os.path.join( + self.lock_file, "%s.%s%s" % (self.hostname, self.tname, self.pid) + ) def acquire(self, timeout=None): timeout = timeout if timeout is not None else self.timeout @@ -47,13 +46,12 @@ class MkdirLockFile(LockBase): return if timeout is not None and time.time() > end_time: if timeout > 0: - raise LockTimeout("Timeout waiting to acquire" - " lock for %s" % - self.path) + raise LockTimeout( + "Timeout waiting to acquire" " lock for %s" % self.path + ) else: # Someone else has the lock. - raise AlreadyLocked("%s is already locked" % - self.path) + raise AlreadyLocked("%s is already locked" % self.path) time.sleep(wait) else: # Couldn't create the lock for some other reason @@ -74,8 +72,7 @@ class MkdirLockFile(LockBase): return os.path.exists(self.lock_file) def i_am_locking(self): - return (self.is_locked() and - os.path.exists(self.unique_name)) + return self.is_locked() and os.path.exists(self.unique_name) def break_lock(self): if os.path.exists(self.lock_file): diff --git a/lockfile/pidlockfile.py b/lockfile/pidlockfile.py index 069e85b..14c4859 100644 --- a/lockfile/pidlockfile.py +++ b/lockfile/pidlockfile.py @@ -18,10 +18,9 @@ import errno import os import time -from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, - LockTimeout) +from . import LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, LockTimeout + - class PIDLockFile(LockBase): """ Lockfile implemented as a Unix PID file. @@ -80,12 +79,11 @@ class PIDLockFile(LockBase): # The lock creation failed. Maybe sleep a bit. if time.time() > end_time: if timeout is not None and timeout > 0: - raise LockTimeout("Timeout waiting to acquire" - " lock for %s" % - self.path) + raise LockTimeout( + "Timeout waiting to acquire" " lock for %s" % self.path + ) else: - raise AlreadyLocked("%s is already locked" % - self.path) + raise AlreadyLocked("%s is already locked" % self.path) time.sleep(timeout is not None and timeout / 10 or 0.1) else: raise LockFailed("failed to create %s" % self.path) @@ -125,7 +123,7 @@ def read_pid_from_pidfile(pidfile_path): """ pid = None try: - pidfile = open(pidfile_path, 'r') + pidfile = open(pidfile_path, "r") except IOError: pass else: @@ -156,10 +154,10 @@ def write_pid_to_pidfile(pidfile_path): and write it to the named file as a line of text. """ - open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) + open_flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY open_mode = 0o644 pidfile_fd = os.open(pidfile_path, open_flags, open_mode) - pidfile = os.fdopen(pidfile_fd, 'w') + pidfile = os.fdopen(pidfile_fd, "w") # According to the FHS 2.3 section on PID files in /var/run: # diff --git a/lockfile/sqlitelockfile.py b/lockfile/sqlitelockfile.py index f997e24..9fa2ab2 100644 --- a/lockfile/sqlitelockfile.py +++ b/lockfile/sqlitelockfile.py @@ -27,6 +27,7 @@ class SQLiteLockFile(LockBase): if SQLiteLockFile.testdb is None: import tempfile + _fd, testdb = tempfile.mkstemp() os.close(_fd) os.unlink(testdb) @@ -34,20 +35,24 @@ class SQLiteLockFile(LockBase): SQLiteLockFile.testdb = testdb import sqlite3 + self.connection = sqlite3.connect(SQLiteLockFile.testdb) c = self.connection.cursor() try: - c.execute("create table locks" - "(" - " lock_file varchar(32)," - " unique_name varchar(32)" - ")") + c.execute( + "create table locks" + "(" + " lock_file varchar(32)," + " unique_name varchar(32)" + ")" + ) except sqlite3.OperationalError: pass else: self.connection.commit() import atexit + atexit.register(os.unlink, SQLiteLockFile.testdb) def acquire(self, timeout=None): @@ -68,32 +73,35 @@ class SQLiteLockFile(LockBase): while True: if not self.is_locked(): # Not locked. Try to lock it. - cursor.execute("insert into locks" - " (lock_file, unique_name)" - " values" - " (?, ?)", - (self.lock_file, self.unique_name)) + cursor.execute( + "insert into locks" + " (lock_file, unique_name)" + " values" + " (?, ?)", + (self.lock_file, self.unique_name), + ) self.connection.commit() # Check to see if we are the only lock holder. - cursor.execute("select * from locks" - " where unique_name = ?", - (self.unique_name,)) + cursor.execute( + "select * from locks" " where unique_name = ?", (self.unique_name,) + ) rows = cursor.fetchall() if len(rows) > 1: # Nope. Someone else got there. Remove our lock. - cursor.execute("delete from locks" - " where unique_name = ?", - (self.unique_name,)) + cursor.execute( + "delete from locks" " where unique_name = ?", + (self.unique_name,), + ) self.connection.commit() else: # Yup. We're done, so go home. return else: # Check to see if we are the only lock holder. - cursor.execute("select * from locks" - " where unique_name = ?", - (self.unique_name,)) + cursor.execute( + "select * from locks" " where unique_name = ?", (self.unique_name,) + ) rows = cursor.fetchall() if len(rows) == 1: # We're the locker, so go home. @@ -103,9 +111,9 @@ class SQLiteLockFile(LockBase): if timeout is not None and time.time() > end_time: if timeout > 0: # No more waiting. - raise LockTimeout("Timeout waiting to acquire" - " lock for %s" % - self.path) + raise LockTimeout( + "Timeout waiting to acquire" " lock for %s" % self.path + ) else: # Someone else has the lock and we are impatient.. raise AlreadyLocked("%s is already locked" % self.path) @@ -117,40 +125,38 @@ class SQLiteLockFile(LockBase): if not self.is_locked(): raise NotLocked("%s is not locked" % self.path) if not self.i_am_locking(): - raise NotMyLock("%s is locked, but not by me (by %s)" % - (self.unique_name, self._who_is_locking())) + raise NotMyLock( + "%s is locked, but not by me (by %s)" + % (self.unique_name, self._who_is_locking()) + ) cursor = self.connection.cursor() - cursor.execute("delete from locks" - " where unique_name = ?", - (self.unique_name,)) + cursor.execute( + "delete from locks" " where unique_name = ?", (self.unique_name,) + ) self.connection.commit() def _who_is_locking(self): cursor = self.connection.cursor() - cursor.execute("select unique_name from locks" - " where lock_file = ?", - (self.lock_file,)) + cursor.execute( + "select unique_name from locks" " where lock_file = ?", (self.lock_file,) + ) return cursor.fetchone()[0] def is_locked(self): cursor = self.connection.cursor() - cursor.execute("select * from locks" - " where lock_file = ?", - (self.lock_file,)) + cursor.execute("select * from locks" " where lock_file = ?", (self.lock_file,)) rows = cursor.fetchall() return not not rows def i_am_locking(self): cursor = self.connection.cursor() - cursor.execute("select * from locks" - " where lock_file = ?" - " and unique_name = ?", - (self.lock_file, self.unique_name)) + cursor.execute( + "select * from locks" " where lock_file = ?" " and unique_name = ?", + (self.lock_file, self.unique_name), + ) return not not cursor.fetchall() def break_lock(self): cursor = self.connection.cursor() - cursor.execute("delete from locks" - " where lock_file = ?", - (self.lock_file,)) + cursor.execute("delete from locks" " where lock_file = ?", (self.lock_file,)) self.connection.commit() diff --git a/lockfile/symlinklockfile.py b/lockfile/symlinklockfile.py index 23b41f5..7bb3c77 100644 --- a/lockfile/symlinklockfile.py +++ b/lockfile/symlinklockfile.py @@ -3,8 +3,7 @@ from __future__ import absolute_import import os import time -from . import (LockBase, NotLocked, NotMyLock, LockTimeout, - AlreadyLocked) +from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked class SymlinkLockFile(LockBase): @@ -40,12 +39,11 @@ class SymlinkLockFile(LockBase): # Otherwise the lock creation failed. if timeout is not None and time.time() > end_time: if timeout > 0: - raise LockTimeout("Timeout waiting to acquire" - " lock for %s" % - self.path) + raise LockTimeout( + "Timeout waiting to acquire" " lock for %s" % self.path + ) else: - raise AlreadyLocked("%s is already locked" % - self.path) + raise AlreadyLocked("%s is already locked" % self.path) time.sleep(timeout / 10 if timeout is not None else 0.1) else: # Link creation succeeded. We're good to go. @@ -62,8 +60,10 @@ class SymlinkLockFile(LockBase): return os.path.islink(self.lock_file) def i_am_locking(self): - return (os.path.islink(self.lock_file) - and os.readlink(self.lock_file) == self.unique_name) + return ( + os.path.islink(self.lock_file) + and os.readlink(self.lock_file) == self.unique_name + ) def break_lock(self): if os.path.islink(self.lock_file): # exists && link