From 973abc928ee0065cf7f50283f10b5acc58a61f86 Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 17 Feb 2013 00:55:25 +0100 Subject: [PATCH 1/5] Support for external file descriptors. Allows to run i3status directly from your __main__, like this: status.register(...) # and so on process = subprocess.Popen("i3status", stdout=subprocess.PIPE) status.fd = process.stdout # start the handler status.run() --- i3pystatus/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index ffeee6f..586f954 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -40,6 +40,7 @@ class IntervalModule(AsyncModule): class I3statusHandler: modules = [] + fd = sys.stdin def __init__(self): pass @@ -61,7 +62,7 @@ class I3statusHandler: # try reading a line, removing any extra whitespace try: - line = sys.stdin.readline().strip() + line = self.fd.readline().decode("utf-8").strip() # i3status sends EOF, or an empty line if not line: sys.exit(3) From ab5afd022726bbd76182831e6ea43bf2ccee01de Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 17 Feb 2013 01:19:04 +0100 Subject: [PATCH 2/5] Moved IO handling out of main class (for reusability; I use that piece of code now elsewhere and want to keep that easily in sync) --- i3pystatus/__init__.py | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index 586f954..bfb38ac 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -38,31 +38,23 @@ class IntervalModule(AsyncModule): self.run() time.sleep(self.interval) -class I3statusHandler: - modules = [] - fd = sys.stdin - - def __init__(self): - pass - - def register(self, module): - """Register a new module.""" - - self.modules.append(module) - module.registered(self) +class IOHandler: + def __init__(self, inp=sys.stdin, out=sys.stdout): + self.inp = inp + self.out = out def print_line(self, message): """Unbuffered printing to stdout.""" - sys.stdout.write(message + "\n") - sys.stdout.flush() + self.out.write(message + "\n") + self.out.flush() def read_line(self): """Interrupted respecting reader for stdin.""" # try reading a line, removing any extra whitespace try: - line = self.fd.readline().decode("utf-8").strip() + line = self.inp.readline().decode("utf-8").strip() # i3status sends EOF, or an empty line if not line: sys.exit(3) @@ -71,12 +63,28 @@ class I3statusHandler: except KeyboardInterrupt: sys.exit() +class I3statusHandler: + modules = [] + fd = sys.stdin + + def __init__(self, fd=None): + if fd is None: + fd = sys.stdin + + self.io = IOHandler(fd) + + def register(self, module): + """Register a new module.""" + + self.modules.append(module) + module.registered(self) + def run(self): - self.print_line(self.read_line()) - self.print_line(self.read_line()) + self.io.print_line(self.io.read_line()) + self.io.print_line(self.io.read_line()) while True: - line, prefix = self.read_line(), "" + line, prefix = self.io.read_line(), "" # ignore comma at start of lines if line.startswith(","): @@ -93,4 +101,4 @@ class I3statusHandler: j.insert(0, output) # and echo back new encoded json - self.print_line(prefix+json.dumps(j)) + self.io.print_line(prefix+json.dumps(j)) From 60b5def7d91f3f051c5a7a94fb628dc12a14419e Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 17 Feb 2013 01:25:41 +0100 Subject: [PATCH 3/5] Splitted IO handling even a bit more :-) --- i3pystatus/__init__.py | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index bfb38ac..602545c 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -43,13 +43,13 @@ class IOHandler: self.inp = inp self.out = out - def print_line(self, message): + def write(self, message): """Unbuffered printing to stdout.""" self.out.write(message + "\n") self.out.flush() - def read_line(self): + def read(self): """Interrupted respecting reader for stdin.""" # try reading a line, removing any extra whitespace @@ -63,9 +63,26 @@ class IOHandler: except KeyboardInterrupt: sys.exit() +class JSONIO: + def __init__(self, io): + self.io = io + self.io.write(self.io.read()) + self.io.write(self.io.read()) + + def write(self, prefix, j): + self.io.write(prefix + json.dumps(j)) + + def read(self): + line, prefix = self.io.read(), "" + + # ignore comma at start of lines + if line.startswith(","): + line, prefix = line[1:], "," + + return (prefix, json.loads(line)) + class I3statusHandler: modules = [] - fd = sys.stdin def __init__(self, fd=None): if fd is None: @@ -80,25 +97,16 @@ class I3statusHandler: module.registered(self) def run(self): - self.io.print_line(self.io.read_line()) - self.io.print_line(self.io.read_line()) + jio = JSONIO(self.io) while True: - line, prefix = self.io.read_line(), "" - - # ignore comma at start of lines - if line.startswith(","): - line, prefix = line[1:], "," - - j = json.loads(line) + prefix, j = jio.read() for module in self.modules: module.tick() output = module.output - if output: j.insert(0, output) - # and echo back new encoded json - self.io.print_line(prefix+json.dumps(j)) + jio.write(prefix, j) From 797333e7ac71d3d06f98a3de25f685b8202acce5 Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 17 Feb 2013 13:57:22 +0100 Subject: [PATCH 4/5] Added some magic to JSONIO --- i3pystatus/__init__.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index 602545c..1233f98 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -69,17 +69,29 @@ class JSONIO: self.io.write(self.io.read()) self.io.write(self.io.read()) - def write(self, prefix, j): - self.io.write(prefix + json.dumps(j)) + self._prefix = "" + + @property + def prefix(self): + prefix = self._prefix + self._prefix = "" + return prefix + + @prefix.setter + def prefix(self, prefix): + self._prefix = prefix + + def write(self, j): + self.io.write(self.prefix + json.dumps(j)) def read(self): - line, prefix = self.io.read(), "" + line, self.prefix = self.io.read(), "" # ignore comma at start of lines if line.startswith(","): - line, prefix = line[1:], "," + line, self.prefix = line[1:], "," - return (prefix, json.loads(line)) + return json.loads(line) class I3statusHandler: modules = [] @@ -100,7 +112,7 @@ class I3statusHandler: jio = JSONIO(self.io) while True: - prefix, j = jio.read() + j = jio.read() for module in self.modules: module.tick() @@ -109,4 +121,4 @@ class I3statusHandler: if output: j.insert(0, output) - jio.write(prefix, j) + jio.write(j) From 84fdbfaff350ff52b7dbe859cf8ef3027c602f80 Mon Sep 17 00:00:00 2001 From: enkore Date: Sun, 17 Feb 2013 14:02:55 +0100 Subject: [PATCH 5/5] Using a context here is much... smoother exploited_language_features += 2; (I also exploit the mutability of the list-object here, yield j binds the list to the context, when the context is leaved execution continues and the modified j is written back) --- i3pystatus/__init__.py | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/i3pystatus/__init__.py b/i3pystatus/__init__.py index 1233f98..6d6f9fa 100644 --- a/i3pystatus/__init__.py +++ b/i3pystatus/__init__.py @@ -5,6 +5,7 @@ import json import urllib.request, urllib.error, urllib.parse from threading import Thread import time +from contextlib import contextmanager class BaseModule: output = None @@ -69,29 +70,18 @@ class JSONIO: self.io.write(self.io.read()) self.io.write(self.io.read()) - self._prefix = "" - - @property - def prefix(self): - prefix = self._prefix - self._prefix = "" - return prefix - - @prefix.setter - def prefix(self, prefix): - self._prefix = prefix - - def write(self, j): - self.io.write(self.prefix + json.dumps(j)) - + @contextmanager def read(self): - line, self.prefix = self.io.read(), "" + line, prefix = self.io.read(), "" # ignore comma at start of lines if line.startswith(","): - line, self.prefix = line[1:], "," + line, prefix = line[1:], "," - return json.loads(line) + j = json.loads(line) + yield j + + self.io.write(prefix + json.dumps(j)) class I3statusHandler: modules = [] @@ -112,13 +102,10 @@ class I3statusHandler: jio = JSONIO(self.io) while True: - j = jio.read() + with jio.read() as j: + for module in self.modules: + module.tick() - for module in self.modules: - module.tick() - - output = module.output - if output: - j.insert(0, output) - - jio.write(j) + output = module.output + if output: + j.insert(0, output)