Mercurial > hg > ooxml
annotate excel.py @ 73:4bd5de7ac247
added Range, M and RC
author | Henry S. Thompson <ht@markup.co.uk> |
---|---|
date | Mon, 03 Jul 2017 16:25:49 +0100 |
parents | 54bb53434887 |
children | 7827e686be75 |
rev | line source |
---|---|
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
1 #!/usr/bin/python3 |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
2 '''Class model for analysis of Excel spreadsheets''' |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
3 from jsonweb.encode import to_object, dumper |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
4 from jsonweb.decode import from_object, loader |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
5 import json |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
6 import eDecoder |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
7 |
73 | 8 import re |
9 | |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
10 try: |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
11 string_types=basestring |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
12 except NameError: |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
13 string_types=str |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
14 |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
15 @from_object() |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
16 @to_object(exclude_nulls=True) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
17 class Book(object): |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
18 def __init__(self,source,sheets=[],formats=[]): |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
19 assert(isinstance(source,string_types)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
20 self.source=source |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
21 sheets=list(sheets) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
22 assert(all(isinstance(s,Sheet) for s in sheets)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
23 self.sheets=sheets |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
24 formats=list(formats) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
25 self.formats=formats |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
26 |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
27 def addSheet(self,sheet): |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
28 assert(isinstance(sheet,Sheet)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
29 self.sheets.append(sheet) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
30 |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
31 @from_object() |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
32 @to_object(exclude_nulls=True,suppress=["book"]) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
33 class Sheet(object): |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
34 def __init__(self,name,book=None,tables=[],docs=[],misc=[]): |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
35 assert(isinstance(name,string_types)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
36 self.name=name |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
37 tables=list(tables) |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
38 assert(all(isinstance(s,Table) for s in tables)) |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
39 self.tables=tables |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
40 docs=list(docs) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
41 assert(all(isinstance(s,Region) for s in docs)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
42 self.docs=docs |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
43 misc=list(misc) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
44 assert(all(isinstance(s,Region) for s in misc)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
45 self.misc=misc |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
46 if book is not None: |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
47 assert(isinstance(book,Book)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
48 book.addSheet(self) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
49 self.book=book |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
50 |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
51 def addTable(self,table): |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
52 assert(isinstance(table,Region)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
53 self.tables.append(table) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
54 |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
55 @from_object() |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
56 @to_object(exclude_nulls=True,suppress=["parent"]) |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
57 class Region(object): |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
58 def __init__(self,name,parent=None,ranges=[],content=[]): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
59 if parent is not None: |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
60 assert(isinstance(parent,(Region,Sheet))) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
61 self.parent=parent |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
62 ranges=list(ranges) |
73 | 63 assert(all(isinstance(s,string_types) for s in ranges)) |
64 self.ranges=[Range(s) for s in ranges] | |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
65 content=list(content) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
66 assert(all(isinstance(s,(Region,string_types)) for s in content)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
67 self.content=content |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
68 assert(isinstance(name,string_types)) |
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
69 self.name=name |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
70 if parent is not None: |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
71 parent.addRegion(self) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
72 |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
73 def addRegion(self,content): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
74 assert(isinstance(content,(Region,string_types))) |
73 | 75 # convert |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
76 self.content.append(content) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
77 |
73 | 78 cell=r'(\$?)([A-Z]+)(\$?)([1-9][0-9]*)' |
79 RANGE=re.compile(cell+(r'(:%s)?'%cell)) | |
80 C=0 # Column | |
81 R=1 # Row | |
82 F=0 # Fixed ($) | |
83 V=1 # Value | |
84 @to_object() | |
85 class Range(object): | |
86 def __init__(self,estr): | |
87 m=RANGE.match(estr) | |
88 if m is None: | |
89 raise ValueError("string %s doesn't represent a range"%estr) | |
90 rgrps=m.groups() | |
91 self.tl=((rgrps[0]=='$',rgrps[1]),((rgrps[2]=='$',int(rgrps[3])))) | |
92 if rgrps[4] is None: | |
93 self.br=None | |
94 self.dim=0 | |
95 self.vertical=None | |
96 else: | |
97 self.br=((rgrps[5]=='$',rgrps[6]),((rgrps[7]=='$',int(rgrps[8])))) | |
98 if self.tl[C][V]==self.br[C][V]: | |
99 self.dim=1 | |
100 self.vertical=True | |
101 elif self.tl[R][V]==self.br[R][V]: | |
102 self.dim=1 | |
103 self.vertical=False | |
104 else: | |
105 self.dim=2 | |
106 self.vertical=None | |
107 | |
108 def __str__(self): | |
109 tls=_cellStr(self.tl[C])+_cellStr(self.tl[R]) | |
110 if self.br is None: | |
111 return tls | |
112 else: | |
113 return '%s:%s'%(tls,_cellStr(self.br[C])+_cellStr(self.br[R])) | |
114 | |
115 def _cellStr(dvp): | |
116 (dollar,val)=dvp | |
117 return '%s%s'%('$' if dollar else '',str(val)) | |
118 | |
119 @from_object() | |
120 @to_object(exclude_nulls=True) | |
121 class M(Region): | |
122 def __init__(self,name,sheet=None,ranges=[],labels=[],data=[]): | |
123 super(M,self).__init__(name,sheet,ranges,labels,data) | |
124 | |
125 @from_object() | |
126 @to_object(exclude_nulls=True) | |
127 class RC(Region): | |
128 def __init__(self,name,sheet=None,ranges=[],labels=[],data=[]): | |
129 super(RC,self).__init__(name,sheet,ranges,labels,data) | |
130 | |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
131 @from_object() |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
132 @to_object(exclude_nulls=True,suppress=["sheet"]) |
73 | 133 class Table(M): |
134 def __init__(self,name,shape='mixed',sheet=None,ranges=[],labels=[],data=[]): | |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
135 super(Table,self).__init__(name,sheet,ranges) |
73 | 136 assert(shape in ('columns','rows','mixed')) |
137 self.shape=shape # if columns or rows, that's what correspond to DB columns | |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
138 labels=list(labels) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
139 assert(all(isinstance(s,Label) for s in labels)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
140 self.labels=labels |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
141 data=list(data) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
142 assert(all(isinstance(s,Region) for s in data)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
143 self.data=data |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
144 if sheet is not None: |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
145 assert(isinstance(sheet,Sheet)) |
70
0003fe7b6b67
beginning work on class structure for excel annotation
Henry S. Thompson <ht@markup.co.uk>
parents:
diff
changeset
|
146 sheet.addTable(self) |
71
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
147 self.sheet=sheet |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
148 |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
149 def addLabel(self,label): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
150 assert(isinstance(label,Label)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
151 self.labels.append(label) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
152 |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
153 def addData(self,data): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
154 assert(isinstance(data,Data)) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
155 self.data.append(data) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
156 |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
157 def addRegion(self,region): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
158 assert(isinstance(region,(Label,Data))) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
159 if isinstance(region,Label): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
160 self.addLabel(region) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
161 else: |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
162 self.addData(region) |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
163 |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
164 def lt(filename): |
54bb53434887
begin work on decoder that allows identifiers as keys and values
Henry S. Thompson <ht@markup.co.uk>
parents:
70
diff
changeset
|
165 with open(filename,'r') as js: |
73 | 166 return loader(js.read(),cls=eDecoder.eDecoder) |