Created
May 10, 2013 14:41
-
-
Save stuaxo/5554827 to your computer and use it in GitHub Desktop.
Access a spreadsheet in the same style as django models. Only gives access to X, Y Avis and 'Fields' - everything else.
Allows named access to these and can easily be extended to munge the data
on the way in. Used originally for writing importers from spreadsheets, can easily use
with csvreader or xlwt. Wrote this quite a while ago, keep finding…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import csv | |
''' | |
Very minimal class for reading cells from 2d structures (e.g. those | |
returned by the csv reader. | |
reader classes extend GridModel and contain a Field and optional XAxis and | |
YAxis | |
class Customers(GridModel): | |
name = XAxis() | |
category = YAxis() | |
age = Field() | |
You can use properties to infer values... | |
class Customers(GridModel): | |
name = XAxis() | |
category = YAxis() | |
age = Field() | |
def __get_centinarian(self): | |
return self.age > 99 | |
centinarian = property(__get_centinarian) | |
''' | |
class FieldModelException(Exception): | |
pass | |
class CellRange: | |
def __init__(self): | |
self.value = None | |
def __str__(self): | |
return str(self.value) | |
class Field(CellRange): | |
def read_cell(self, (x, y), value): | |
""" | |
""" | |
if x is not 0 and y is not 0: | |
self.value = value | |
return True | |
class XAxis(CellRange): | |
""" | |
Store values on the XAxis. After calling read_cell, the current XAxis | |
value will be available in value | |
""" | |
def __init__(self): | |
self.value = None | |
self.values = {} | |
def read_cell(self, (x, y), value): | |
if y is 0: | |
self.values[x] = value | |
return True | |
self.value = self.values[x] | |
class YAxis(CellRange): | |
""" | |
Store values on the YAxis. After calling read_cell, the current YAxis | |
value will be available in value | |
""" | |
def __init__(self): | |
self.value = None | |
self.values = {} | |
def read_cell(self, (x, y), value): | |
if x is 0: | |
self.values[y] = value | |
return True | |
self.value = self.values[y] | |
class _GridModel(type): | |
""" | |
The Metaclass for GridModel | |
""" | |
def __new__(meta, name, bases, attrs): | |
cellattr = None | |
metadata = [] | |
for attr, cls in attrs.items(): | |
if hasattr(cls, '__class__') and cls.__class__.__name__ == 'Field': | |
if cellattr is not None: | |
raise FieldModelException('Cells added to FieldModel more than once') | |
cellattr = attr | |
else: | |
if isinstance(cls, CellRange): | |
# For fields added, cls is set to None at this point | |
metadata.append(attr) | |
attrs['__cell_attr__'] = cellattr | |
attrs['__metadata_attrs__'] = metadata | |
return type.__new__(meta, name, bases, attrs) | |
class GridModel: | |
__metaclass__ = _GridModel | |
def __init__(self): | |
# Get instance of __cellattr__ into __cells__ | |
self.__cells__ = getattr(self.__class__, self.__cell_attr__) | |
self.__metadata__ = [] | |
for field in self.__metadata_attrs__: | |
self.__metadata__.append(getattr(self, field)) | |
def read_cells(self, data): | |
""" | |
Generator function, reads 2d data, yields data from cells only | |
""" | |
for y, row in enumerate(data): | |
for x, value in enumerate(row): | |
for handler in self.__metadata__: | |
handler.read_cell((x, y), value) | |
if self.__cells__.read_cell((x, y), value): | |
yield(self) | |
def __str__(self): | |
return str(self.__cells__.value) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment