The following code does three things:
- The filename is determined by the RawData class
- The reader and writer send data through a processing pipeline
- (Hopefully) makes changes and extensions easy
Regarding (2), the processing pipeline consists of "processors", that can process and deprocess data. For example, if you run the code below and look in ortho_animals.txt
, you'll see the JSON version of a dict with (keys, values) reversed.
I left comments out to keep the size of the code to a minimum. Please let me know what you think, with a particular eye on the class designs and interactions.
import contextlib
import json
class Processor(object):
@classmethod
def process(cls, data):
raise NotImplementedError
@classmethod
def deprocess(cls, data):
raise NotImplementedError
class JsonProcessor(Processor):
@classmethod
def process(cls, data):
return json.dumps(data)
@classmethod
def deprocess(cls, data):
return json.loads(data)
class SwapProcessor(Processor):
@classmethod
def process(cls, data):
return cls.swap(data)
@classmethod
def deprocess(cls, data):
return cls.swap(data)
@classmethod
def swap(cls, data):
return {v: k for k, v in data.iteritems()}
class AggregateProcessor(Processor):
def __init__(self, processors):
self.processors = processors
def process(self, data):
return reduce(lambda d, kls: kls.process(d), self.processors, data)
def deprocess(self, data):
return reduce(lambda d, kls: kls.deprocess(d), self.processors[::-1], data)
class RawReader(object):
def __init__(self, file_obj, processor):
self._file = file_obj
self._processor = processor
def read(self):
data = self._file.read()
return self._processor.deprocess(data)
class RawWriter(object):
def __init__(self, file_obj, processor):
self._file = file_obj
self._processor = processor
def write(self, data):
new_data = self._processor.process(data)
self._file.write(new_data)
class RawData(object):
processors = [SwapProcessor, JsonProcessor]
aggregator = AggregateProcessor(processors)
def __init__(self, obj_type, key):
self.obj_type = obj_type
self.key = key
def _build_filename(self):
return self.obj_type + '_' + self.key + '.txt'
@contextlib.contextmanager
def writer(self):
filename = self._build_filename()
with open(filename, 'w') as f:
yield RawWriter(f, self.aggregator)
@contextlib.contextmanager
def reader(self):
filename = self._build_filename()
with open(filename, 'r') as f:
yield RawReader(f, self.aggregator)
if __name__ == '__main__':
data = {'cats': 'suck', 'dogs': 'rule'}
rd = RawData('ortho', key='animals')
with rd.writer() as writer:
writer.write(data)
with rd.reader() as reader:
new_data = reader.read()
assert(new_data['cats'] == data['cats'])