From a9077d83083c66057f4ffd51651480f37ee1a4e2 Mon Sep 17 00:00:00 2001 From: Mike Bloy Date: Sun, 21 Jan 2024 13:10:31 -0600 Subject: [PATCH] ex 8.1, 8.2, 8.3 --- .gitignore | 1 + cofollow.py | 34 +++++++++++++++++++++++++++++++ coticker.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ follow.py | 23 +++++++++++++++++++++ structure.py | 13 +++++++++++- ticker.py | 28 ++++++++++++++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 cofollow.py create mode 100644 coticker.py create mode 100644 follow.py create mode 100644 ticker.py diff --git a/.gitignore b/.gitignore index 8a92c10..7322424 100644 --- a/.gitignore +++ b/.gitignore @@ -159,3 +159,4 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ Session.vim +Data/stocklog.csv diff --git a/cofollow.py b/cofollow.py new file mode 100644 index 0000000..f12faa7 --- /dev/null +++ b/cofollow.py @@ -0,0 +1,34 @@ +import os +import time +from functools import wraps + + +def follow(filename, target): + with open(filename, 'r') as f: + f.seek(0, os.SEEK_END) + while True: + line = f.readline() + if line != '': + target.send(line) + else: + time.sleep(0.1) + + +def consumer(func): + @wraps(func) + def start(*args, **kwargs): + f = func(*args, **kwargs) + f.send(None) + return f + return start + + +@consumer +def printer(): + while True: + item = yield + print(item) + + +if __name__ == '__main__': + follow('Data/stocklog.csv', printer()) diff --git a/coticker.py b/coticker.py new file mode 100644 index 0000000..126c4b7 --- /dev/null +++ b/coticker.py @@ -0,0 +1,57 @@ +import csv + +from cofollow import consumer +from tableformat import create_formatter +from ticker import Ticker + + +@consumer +def to_csv(target): + def producer(): + while True: + yield line + + reader = csv.reader(producer()) + while True: + line = yield + target.send(next(reader)) + + +@consumer +def create_ticker(target): + while True: + row = yield + target.send(Ticker.from_row(row)) + + +@consumer +def negchange(target): + while True: + record = yield + if record.change < 0: + target.send(record) + + +@consumer +def ticker(fmt, fields): + formatter = create_formatter(fmt) + formatter.headings(fields) + while True: + rec = yield + row = [getattr(rec, name) for name in fields] + formatter.row(row) + + +if __name__ == '__main__': + from cofollow import follow + + follow( + 'Data/stocklog.csv', + to_csv( + create_ticker( + negchange( + ticker('text', ['name', 'price', 'change']) + ) + ) + ) + ) diff --git a/follow.py b/follow.py new file mode 100644 index 0000000..2a92eab --- /dev/null +++ b/follow.py @@ -0,0 +1,23 @@ +import os +import time + + +def follow(filename): + f = open(filename) + f.seek(0, os.SEEK_END) + while True: + line = f.readline() + if line == '': + time.sleep(0.1) + continue + yield line + + +if __name__ == '__main__': + for line in follow('Data/stocklog.csv'): + fields = line.split(',') + name = fields[0].strip('"') + price = float(fields[1]) + change = float(fields[4]) + if change < 0: + print(f"{name:s} {price:10.2f} {change:10.2f}") diff --git a/structure.py b/structure.py index e07d647..c0407d0 100644 --- a/structure.py +++ b/structure.py @@ -35,7 +35,7 @@ class Structure(metaclass=StructureMeta): validate_attributes(cls) def __repr__(self): - args = map(lambda field: f"{field}={getattr(self, field)!r}", self._fields) + args = map(lambda field: f"{getattr(self, field)!r}", self._fields) return f"{type(self).__name__}({', '.join(args)})" def __setattr__(self, name, value): @@ -44,6 +44,13 @@ class Structure(metaclass=StructureMeta): else: raise AttributeError(f"No attribute {name}") + def __iter__(self): + for name in self._fields: + yield getattr(self, name) + + def __eq__(self, other): + return isinstance(other, type(self)) and tuple(self) == tuple(other) + @classmethod def create_init(cls): code = f'def __init__(self, {", ".join(cls._fields)}):\n' @@ -53,6 +60,10 @@ class Structure(metaclass=StructureMeta): exec(code, locs) cls.__init__ = locs['__init__'] + @classmethod + def from_row(cls, row): + return cls(*[func(val) for func, val in zip(cls._types, row)]) + def typed_structure(clsname, **validators): cls = type(clsname, (Structure,), validators) diff --git a/ticker.py b/ticker.py new file mode 100644 index 0000000..90b1d44 --- /dev/null +++ b/ticker.py @@ -0,0 +1,28 @@ +from structure import Structure + + +class Ticker(Structure): + name = String() + price = Float() + date = String() + time = String() + change = Float() + open = Float() + high = Float() + low = Float() + volume = Integer() + + +if __name__ == '__main__': + import csv + + from follow import follow + from tableformat import create_formatter, print_table + + formatter = create_formatter('text') + + lines = follow('Data/stocklog.csv') + rows = csv.reader(lines) + records = (Ticker.from_row(row) for row in rows) + negative = (rec for rec in records if rec.change < 0) + print_table(negative, ['name', 'price', 'change'], formatter)