From b42cd6aa1553f45d9b77e6edd5ba9d584935f9b3 Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 10 Mar 2013 21:22:58 +0100 Subject: [PATCH] 3.12: Move code around --- i3pystatus/__init__.py | 5 +- i3pystatus/core/__init__.py | 4 +- i3pystatus/core/io.py | 2 +- i3pystatus/core/modules.py | 15 +-- i3pystatus/core/threading/__init__.py | 2 + i3pystatus/core/threading/manager.py | 49 ++++++++++ i3pystatus/core/threading/threads.py | 53 +++++++++++ i3pystatus/core/threading/wrapper.py | 30 ++++++ i3pystatus/core/threads.py | 131 -------------------------- i3pystatus/core/util.py | 4 - i3pystatus/runwatch.py | 6 +- setup.py | 7 +- 12 files changed, 152 insertions(+), 156 deletions(-) create mode 100644 i3pystatus/core/threading/__init__.py create mode 100644 i3pystatus/core/threading/manager.py create mode 100644 i3pystatus/core/threading/threads.py create mode 100644 i3pystatus/core/threading/wrapper.py delete mode 100644 i3pystatus/core/threads.py diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index 7bc4e5f..3fd11f7 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -3,14 +3,14 @@ import sys from .core import Status -from .core.modules import Module, AsyncModule, IntervalModule +from .core.modules import Module, IntervalModule from .core.settings import SettingsBase from .core.config import ConfigFinder from .core.render import render_json __all__ = [ "SettingsBase", - "Module", "AsyncModule", "IntervalModule", + "Module", "IntervalModule", "Status", ] @@ -25,7 +25,6 @@ def test_config(): def run(self): self.call_start_hooks() for module in self.modules: - sys.stdout.write("{module}: ".format(module=module.__name__)) sys.stdout.flush() module.run() diff --git a/i3pystatus/core/__init__.py b/i3pystatus/core/__init__.py index 1788644..17d6f8b 100644 --- a/i3pystatus/core/__init__.py +++ b/i3pystatus/core/__init__.py @@ -1,7 +1,7 @@ import sys -import threading import os +from threading import Thread from . import io, util from .modules import Module, START_HOOKS @@ -11,7 +11,7 @@ class Status: self.standalone = standalone if standalone: self.io = io.StandaloneIO(interval) - self.ce_thread = threading.Thread(target=self.run_command_endpoint) + self.ce_thread = Thread(target=self.run_command_endpoint) self.ce_thread.daemon = True self.ce_thread.start() else: diff --git a/i3pystatus/core/io.py b/i3pystatus/core/io.py index a56bdea..a7b80d2 100644 --- a/i3pystatus/core/io.py +++ b/i3pystatus/core/io.py @@ -51,7 +51,7 @@ class StandaloneIO(IOHandler): """ n = -1 - proto = ('{"version":1,"bidirectional":true}', "[", "[]", ",[]", ) + proto = ('{"version":1,"bidirectional":true}', "[", "[]", ",[]",) def __init__(self, interval=1): super().__init__() diff --git a/i3pystatus/core/modules.py b/i3pystatus/core/modules.py index 443d115..a70de73 100644 --- a/i3pystatus/core/modules.py +++ b/i3pystatus/core/modules.py @@ -1,8 +1,8 @@ -from threading import Thread + import time from .settings import SettingsBase -from .threads import AutomagicManager +from .threading import Manager __all__ = [ "Module", "AsyncModule", "IntervalModule", @@ -36,15 +36,6 @@ class Module(SettingsBase): def __repr__(self): return self.__class__.__name__ -class AsyncModule(Module): - def registered(self, status_handler): - self.thread = Thread(target=self.mainloop) - self.thread.daemon = True - self.thread.start() - - def mainloop(self): - """This is run in a separate daemon-thread""" - class IntervalModule(Module): interval = 5 # seconds managers = {} @@ -53,7 +44,7 @@ class IntervalModule(Module): if self.interval in IntervalModule.managers: IntervalModule.managers[self.interval].append(self) else: - am = AutomagicManager(self.interval) + am = Manager(self.interval) am.append(self) IntervalModule.managers[self.interval] = am diff --git a/i3pystatus/core/threading/__init__.py b/i3pystatus/core/threading/__init__.py new file mode 100644 index 0000000..7ab2262 --- /dev/null +++ b/i3pystatus/core/threading/__init__.py @@ -0,0 +1,2 @@ + +from .manager import Manager diff --git a/i3pystatus/core/threading/manager.py b/i3pystatus/core/threading/manager.py new file mode 100644 index 0000000..1d91b98 --- /dev/null +++ b/i3pystatus/core/threading/manager.py @@ -0,0 +1,49 @@ + +from ..util import partition +from . import threads, wrapper + +class Manager: + def __init__(self, target_interval): + self.target_interval = target_interval + self.upper_bound = target_interval * 1.1 + self.lower_bound = target_interval * 0.7 + + initial_thread = threads.Thread(target_interval, [self.wrap(self)]) + self.threads = [initial_thread] + + def __call__(self): + separate = [] + for thread in self.threads: + separate.extend(self.branch(thread, thread.time)) + self.create_threads(self.partition(separate)) + + def __repr__(self): + return "Manager" + + def wrap(self, workload): + return wrapper.WorkloadWrapper(wrapper.ExceptionWrapper(workload)) + + def branch(self, thread, vtime): + if len(thread) > 1 and vtime > self.upper_bound: + remove = thread.pop() + return [remove] + self.branch(thread, vtime - remove.time) + return [] + + def partition(self, workloads): + return partition(workloads, self.lower_bound, lambda workload: workload.time) + + def create_threads(self, threads): + for workloads in threads: + self.create_thread(workloads) + + def create_thread(self, workloads): + thread = threads.Thread(self.target_interval, workloads, start_barrier=0) + thread.start() + self.threads.append(thread) + + def append(self, workload): + self.threads[0].append(self.wrap(workload)) + + def start(self): + for thread in self.threads: + thread.start() diff --git a/i3pystatus/core/threading/threads.py b/i3pystatus/core/threading/threads.py new file mode 100644 index 0000000..28999f0 --- /dev/null +++ b/i3pystatus/core/threading/threads.py @@ -0,0 +1,53 @@ + +import time +import threading + +try: + from setproctitle import setproctitle +except ImportError: + def setproctitle(title): + pass + +class Thread(threading.Thread): + def __init__(self, target_interval, workloads=None, start_barrier=1): + super().__init__() + self.workloads = workloads or [] + self.target_interval = target_interval + self.start_barrier = start_barrier + self.daemon = True + + def __iter__(self): + return iter(self.workloads) + + def __len__(self): + return len(self.workloads) + + def pop(self): + return self.workloads.pop() + + def append(self, workload): + self.workloads.append(workload) + + @property + def time(self): + return sum(map(lambda workload: workload.time, self)) + + def wait_for_start_barrier(self): + while len(self) <= self.start_barrier: + time.sleep(0.4) + + def setproctitle(self): + setproctitle("i3pystatus {name}: {workloads}".format(name=self.name, workloads=list(map(repr, self.workloads)))) + + def execute_workloads(self): + for workload in self: + workload() + self.workloads.sort(key=lambda workload: workload.time) + + def run(self): + self.setproctitle() + while self: + self.execute_workloads() + filltime = self.target_interval - self.time + if filltime > 0: + time.sleep(filltime) diff --git a/i3pystatus/core/threading/wrapper.py b/i3pystatus/core/threading/wrapper.py new file mode 100644 index 0000000..24b5716 --- /dev/null +++ b/i3pystatus/core/threading/wrapper.py @@ -0,0 +1,30 @@ + +import sys +import time +import traceback + +timer = time.perf_counter if hasattr(time, "perf_counter") else time.clock + +class Wrapper: + def __init__(self, workload): + self.workload = workload + + def __repr__(self): + return repr(self.workload) + +class ExceptionWrapper(Wrapper): + def __call__(self): + try: + self.workload() + except Exception as exc: + sys.stderr.write("Exception in {thread}".format(thread=threading.current_thread().name)) + traceback.print_exception(*sys.exc_info(), file=sys.stderr) + sys.stderr.flush() + +class WorkloadWrapper(Wrapper): + time = 0.0 + + def __call__(self): + tp1 = timer() + self.workload() + self.time = timer() - tp1 diff --git a/i3pystatus/core/threads.py b/i3pystatus/core/threads.py deleted file mode 100644 index 4392bcc..0000000 --- a/i3pystatus/core/threads.py +++ /dev/null @@ -1,131 +0,0 @@ -import sys -import threading -import time -import traceback - -from .util import partition - -try: - from setproctitle import setproctitle -except ImportError: - def setproctitle(title): - pass - -timer = time.perf_counter if hasattr(time, "perf_counter") else time.clock - -class Wrapper: - def __init__(self, workload): - self.workload = workload - - def __repr__(self): - return repr(self.workload) - -class ExceptionWrapper(Wrapper): - def __call__(self): - try: - self.workload() - except Exception as exc: - sys.stderr.write("Exception in {thread}".format(thread=threading.current_thread().name)) - traceback.print_exception(*sys.exc_info(), file=sys.stderr) - sys.stderr.flush() - -class WorkloadWrapper(Wrapper): - time = 0.0 - - def __call__(self): - tp1 = timer() - self.workload() - self.time = timer() - tp1 - -class Thread(threading.Thread): - def __init__(self, target_interval, workloads=None, start_barrier=1): - super().__init__() - self.workloads = workloads or [] - self.target_interval = target_interval - self.start_barrier = start_barrier - self.daemon = True - - def __iter__(self): - return iter(self.workloads) - - def __len__(self): - return len(self.workloads) - - def pop(self): - return self.workloads.pop() - - def append(self, workload): - self.workloads.append(workload) - - @property - def time(self): - return sum(map(lambda workload: workload.time, self)) - - def wait_for_start_barrier(self): - while len(self) <= self.start_barrier: - time.sleep(0.4) - - def setproctitle(self): - setproctitle("i3pystatus {name}: {workloads}".format(name=self.name, workloads=list(map(repr, self.workloads)))) - - def execute_workloads(self): - for workload in self: - workload() - self.workloads.sort(key=lambda workload: workload.time) - - def run(self): - self.setproctitle() - while self: - self.execute_workloads() - filltime = self.target_interval - self.time - if filltime > 0: - time.sleep(filltime) - -class AutomagicManager: - def __init__(self, target_interval): - self.target_interval = target_interval - self.upper_bound = target_interval * 1.1 - self.lower_bound = target_interval * 0.7 - - initial_thread = Thread(target_interval, [self.wrap(self)]) - self.threads = [initial_thread] - - def __call__(self): - separate = [] - for thread in self.threads: - separate.extend(self.branch(thread, thread.time)) - self.create_threads(self.partition(separate)) - - def __repr__(self): - return "Manager" - - def wrap(self, workload): - return WorkloadWrapper(ExceptionWrapper(workload)) - -# def calculate_sparse_times(): -# return ((self.lower_bound - thread.time, thread) for thread in self.threads) - - def branch(self, thread, vtime): - if len(thread) > 1 and vtime > self.upper_bound: - remove = thread.pop() - return [remove] + self.branch(thread, vtime - remove.time) - return [] - - def partition(self, workloads): - return partition(workloads, self.lower_bound, lambda workload: workload.time) - - def create_threads(self, threads): - for workloads in threads: - self.create_thread(workloads) - - def create_thread(self, workloads): - thread = Thread(self.target_interval, workloads, start_barrier=0) - thread.start() - self.threads.append(thread) - - def append(self, workload): - self.threads[0].append(self.wrap(workload)) - - def start(self): - for thread in self.threads: - thread.start() diff --git a/i3pystatus/core/util.py b/i3pystatus/core/util.py index 4195ee3..2334ee4 100644 --- a/i3pystatus/core/util.py +++ b/i3pystatus/core/util.py @@ -5,10 +5,6 @@ import itertools from .exceptions import * from .imputil import ClassFinder -__all__ = [ - "ModuleList", "KeyConstraintDict", "PrefixedKeyDict", -] - def lchop(string, prefix): if string.startswith(prefix): return string[len(prefix):] diff --git a/i3pystatus/runwatch.py b/i3pystatus/runwatch.py index 5915e7e..115b22a 100644 --- a/i3pystatus/runwatch.py +++ b/i3pystatus/runwatch.py @@ -5,9 +5,11 @@ from i3pystatus import IntervalModule class RunWatch(IntervalModule): """ - Expands the given path using glob to a pidfile and checks if the process ID found inside is valid + Expands the given path using glob to a pidfile and checks + if the process ID found inside is valid (that is, if the process is running). - You can use this to check if a specific application, such as a VPN client or your DHCP client is running. + You can use this to check if a specific application, + such as a VPN client or your DHCP client is running. Available formatters are {pid} and {name}. """ diff --git a/setup.py b/setup.py index a68c831..2f7d262 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,12 @@ setup(name="i3pystatus", "Topic :: Desktop Environment :: Window Managers", ], - packages=["i3pystatus", "i3pystatus.core", "i3pystatus.mail"], + packages=[ + "i3pystatus", + "i3pystatus.core", + "i3pystatus.core.threading", + "i3pystatus.mail" + ], entry_points={ "console_scripts": ["i3pystatus = i3pystatus:main"], },