pyodsstream 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyodsstream/__init__.py +6 -0
- pyodsstream/calc_reader_interface.py +31 -0
- pyodsstream/calc_writer_interface.py +106 -0
- pyodsstream/odsmembers/__init__.py +0 -0
- pyodsstream/odsmembers/content_xml.py +440 -0
- pyodsstream/odsmembers/data/__init__.py +0 -0
- pyodsstream/odsmembers/data/content_part1.xml +42 -0
- pyodsstream/odsmembers/data/contents.xml +2964 -0
- pyodsstream/odsmembers/data/manifest.xml +26 -0
- pyodsstream/odsmembers/data/meta.xml +39 -0
- pyodsstream/odsmembers/data/settings.xml +429 -0
- pyodsstream/odsmembers/data/styles.xml +103 -0
- pyodsstream/odsmembers/meta_xml.py +51 -0
- pyodsstream/odsmembers/options/__init__.py +0 -0
- pyodsstream/odsmembers/options/ods_table_cell_style.py +37 -0
- pyodsstream/odsmembers/sax/__init__.py +0 -0
- pyodsstream/odsmembers/sax/xmlodscontenthandler.py +84 -0
- pyodsstream/odsmembers/sax/xmlodscontenthandler_yield.py +84 -0
- pyodsstream/readers/__init__.py +0 -0
- pyodsstream/readers/ods_doc_reader.py +170 -0
- pyodsstream/readers/tsv_reader.py +150 -0
- pyodsstream/writers/__init__.py +0 -0
- pyodsstream/writers/ods_doc_writer.py +121 -0
- pyodsstream/writers/tsv_directory_writer.py +105 -0
- pyodsstream-0.0.7.dist-info/METADATA +75 -0
- pyodsstream-0.0.7.dist-info/RECORD +29 -0
- pyodsstream-0.0.7.dist-info/WHEEL +5 -0
- pyodsstream-0.0.7.dist-info/licenses/LICENSE +232 -0
- pyodsstream-0.0.7.dist-info/top_level.txt +1 -0
pyodsstream/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from .calc_reader_interface import CalcReaderInterface
|
|
2
|
+
from .calc_writer_interface import CalcWriterInterface
|
|
3
|
+
from .readers.ods_doc_reader import OdsDocReader
|
|
4
|
+
from .readers.tsv_reader import TsvReader
|
|
5
|
+
from .writers.ods_doc_writer import OdsDocWriter
|
|
6
|
+
from .writers.tsv_directory_writer import TsvDirectoryWriter
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# This file is part of pyodsstream.
|
|
2
|
+
#
|
|
3
|
+
# pyodsstream is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# pyodsstream is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with pyodsstream. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CalcReaderInterface(ABC):
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def yield_sheet_lines(self) -> Any:
|
|
25
|
+
"""yield each line from the table"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def line_position(self) -> int:
|
|
30
|
+
"""get the current line position while reading"""
|
|
31
|
+
pass
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# This file is part of pyodsstream.
|
|
2
|
+
#
|
|
3
|
+
# pyodsstream is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# pyodsstream is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with pyodsstream. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import datetime
|
|
19
|
+
from abc import ABC, abstractmethod
|
|
20
|
+
|
|
21
|
+
from matplotlib.typing import ColorType
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class CalcWriterInterface(ABC):
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def close(self):
|
|
27
|
+
"""close the stream/document/file"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def write_sheet(self, sheet_name: str):
|
|
32
|
+
"""open a new sheet
|
|
33
|
+
sheetName the sheet name"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def write_line(self):
|
|
38
|
+
"""open a new line"""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def write_cell(
|
|
43
|
+
self, value: str | int | float | bool | datetime.datetime | datetime.date | None
|
|
44
|
+
):
|
|
45
|
+
"""write a cell"""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def write_cell_percentage(self, value: float):
|
|
50
|
+
"""write a double as a percentage
|
|
51
|
+
# *param number double to write must be a ratio (0.5 == 50%)"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def write_cell_url(self, the_url: str, caption: str):
|
|
56
|
+
"""write a text cell with an URL link
|
|
57
|
+
# * param url_link URL link
|
|
58
|
+
# * param text text to write"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def write_cell_annotation(self, annotation: str):
|
|
63
|
+
"""set annotation to write in the next cell
|
|
64
|
+
annotation any comment on this cell"""
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def reference_ods_table_cell_style(
|
|
68
|
+
self, foreground_color: ColorType, background_color: ColorType
|
|
69
|
+
) -> str:
|
|
70
|
+
"""build table cell style reference with a style definition
|
|
71
|
+
return OdsTableCellStyleRef str on a style reference"""
|
|
72
|
+
return ""
|
|
73
|
+
|
|
74
|
+
def set_ods_table_cell_style_reference(self, cell_ref: str):
|
|
75
|
+
"""set the cell table style. This is applied to in the stream to following
|
|
76
|
+
# * cells. This ends by using an other style reference or by using
|
|
77
|
+
# * setTableCellStyleRef function"""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# /**
|
|
82
|
+
# * clear cell style definition in the stream. the default style will be
|
|
83
|
+
# * applied.
|
|
84
|
+
# *
|
|
85
|
+
# */
|
|
86
|
+
# void clearTableCellStyleRef();
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# /** \brief apply solor scale conditional format on a cell range
|
|
90
|
+
# *
|
|
91
|
+
# */
|
|
92
|
+
# virtual void
|
|
93
|
+
# addColorScale([[maybe_unused]] const OdsColorScale &ods_color_scale);
|
|
94
|
+
|
|
95
|
+
# /** @brief get the last written cell coordinate in ODS coordinate format
|
|
96
|
+
# * get the coordinate of the last written cell or an empty string if the
|
|
97
|
+
# * writer is not an OdsDocWriter
|
|
98
|
+
# *
|
|
99
|
+
# * @return QString with ODS cell coordinate of the form : "classeur.A5"
|
|
100
|
+
# */
|
|
101
|
+
# virtual QString getOdsCellCoordinate();
|
|
102
|
+
|
|
103
|
+
# /** @brief set ODS table settings of the current sheet (table)
|
|
104
|
+
# */
|
|
105
|
+
# virtual void
|
|
106
|
+
# setCurrentOdsTableSettings([[maybe_unused]] const OdsTableSettings &settings);
|
|
File without changes
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# This file is part of pyodsstream.
|
|
2
|
+
#
|
|
3
|
+
# pyodsstream is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# pyodsstream is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with pyodsstream. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import datetime
|
|
18
|
+
import zipfile
|
|
19
|
+
from xml.etree.ElementTree import Element, SubElement, tostring
|
|
20
|
+
|
|
21
|
+
import importlib_resources as resources
|
|
22
|
+
from matplotlib.typing import ColorType
|
|
23
|
+
|
|
24
|
+
from .meta_xml import date_specific_iso
|
|
25
|
+
from .options.ods_table_cell_style import OdsTableCellStyle
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def str_xml_encode(str_value: str):
|
|
29
|
+
text_p = Element("pure_xml_quote", name=str_value)
|
|
30
|
+
new_str = tostring(text_p, encoding="utf-8").decode("utf-8")
|
|
31
|
+
return new_str[22:][:-4]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ContentXml:
|
|
35
|
+
def __init__(self, zf: zipfile.ZipFile):
|
|
36
|
+
self._zfile = zf.open(name="content.xml", mode="w", force_zip64=False)
|
|
37
|
+
ref = resources.files("pyodsstream") / "odsmembers/data/content_part1.xml"
|
|
38
|
+
# Reading the resource
|
|
39
|
+
with ref.open("r") as file:
|
|
40
|
+
self._zfile.write(file.read().encode())
|
|
41
|
+
self._spreadsheet_started = False
|
|
42
|
+
self._table_started = False
|
|
43
|
+
self._table_row_started = False
|
|
44
|
+
self._current_sheet_name = None
|
|
45
|
+
self._row_pos = 0
|
|
46
|
+
self._col_pos = 0
|
|
47
|
+
self._current_style_ref = None
|
|
48
|
+
self._automatic_styles_writed = False
|
|
49
|
+
self._ods_table_cell_style_list = []
|
|
50
|
+
|
|
51
|
+
def _write_automatic_styles(self):
|
|
52
|
+
|
|
53
|
+
if self._automatic_styles_writed:
|
|
54
|
+
return
|
|
55
|
+
self._automatic_styles_writed = True
|
|
56
|
+
|
|
57
|
+
automatic_styles = Element("office:automatic-styles")
|
|
58
|
+
style = SubElement(automatic_styles, "style:style")
|
|
59
|
+
style.attrib["style:name"] = "ce1"
|
|
60
|
+
style.attrib["style:family"] = "table-cell"
|
|
61
|
+
style.attrib["style:parent-style-name"] = "Default"
|
|
62
|
+
style.attrib["style:data-style-name"] = "N0"
|
|
63
|
+
|
|
64
|
+
style2 = SubElement(automatic_styles, "style:style")
|
|
65
|
+
style2.attrib["style:name"] = "ce2"
|
|
66
|
+
style2.attrib["style:family"] = "table-cell"
|
|
67
|
+
style2.attrib["style:parent-style-name"] = "Default"
|
|
68
|
+
style2.attrib["style:data-style-name"] = "N36"
|
|
69
|
+
|
|
70
|
+
co1 = SubElement(automatic_styles, "style:style")
|
|
71
|
+
co1.attrib["style:name"] = "co1"
|
|
72
|
+
co1.attrib["style:family"] = "table-column"
|
|
73
|
+
subco1 = SubElement(co1, "style:table-column-properties")
|
|
74
|
+
subco1.attrib["fo:break-before"] = "auto"
|
|
75
|
+
subco1.attrib["style:column-width"] = "2.27541666666667cm"
|
|
76
|
+
|
|
77
|
+
co2 = SubElement(automatic_styles, "style:style")
|
|
78
|
+
co2.attrib["style:name"] = "co2"
|
|
79
|
+
co2.attrib["style:family"] = "table-column"
|
|
80
|
+
subco1 = SubElement(co2, "style:table-column-properties")
|
|
81
|
+
subco1.attrib["fo:break-before"] = "auto"
|
|
82
|
+
subco1.attrib["style:column-width"] = "2.27541666666667cm"
|
|
83
|
+
|
|
84
|
+
ro1 = SubElement(automatic_styles, "style:style")
|
|
85
|
+
ro1.attrib["style:name"] = "ro1"
|
|
86
|
+
ro1.attrib["style:family"] = "table-row"
|
|
87
|
+
subro1 = SubElement(ro1, "style:table-row-properties")
|
|
88
|
+
subro1.attrib["style:row-height"] = "15pt"
|
|
89
|
+
subro1.attrib["style:use-optimal-row-height"] = "true"
|
|
90
|
+
subro1.attrib["fo:break-before"] = "auto"
|
|
91
|
+
|
|
92
|
+
ta1 = SubElement(automatic_styles, "style:style")
|
|
93
|
+
ta1.attrib["style:name"] = "ta1"
|
|
94
|
+
ta1.attrib["style:family"] = "table"
|
|
95
|
+
ta1.attrib["style:master-page-name"] = "mp1"
|
|
96
|
+
subta1 = SubElement(ta1, "style:table-properties")
|
|
97
|
+
subta1.attrib["table:display"] = "true"
|
|
98
|
+
subta1.attrib["style:writing-mode"] = "lr-tb"
|
|
99
|
+
|
|
100
|
+
for ods_table_cell_style in self._ods_table_cell_style_list:
|
|
101
|
+
ref_style = SubElement(automatic_styles, "style:style")
|
|
102
|
+
ref_style.attrib["style:name"] = ods_table_cell_style.xml_ref
|
|
103
|
+
ref_style.attrib["style:family"] = "table-cell"
|
|
104
|
+
ref_style.attrib["style:parent-style-name"] = "Default"
|
|
105
|
+
ref_style.attrib["style:data-style-name"] = "N0"
|
|
106
|
+
sub_ref_style_bkg = SubElement(ref_style, "style:table-cell-properties")
|
|
107
|
+
sub_ref_style_bkg.attrib["fo:background-color"] = (
|
|
108
|
+
ods_table_cell_style.background_color
|
|
109
|
+
)
|
|
110
|
+
sub_ref_style = SubElement(ref_style, "style:text-properties")
|
|
111
|
+
sub_ref_style.attrib["fo:color"] = ods_table_cell_style.color
|
|
112
|
+
|
|
113
|
+
str_text = tostring(automatic_styles, encoding="utf-8").decode("utf-8")
|
|
114
|
+
|
|
115
|
+
# print(str_text)
|
|
116
|
+
self._zfile.write(str_text.encode())
|
|
117
|
+
# <office:automatic-styles>
|
|
118
|
+
# <style:style
|
|
119
|
+
# style:name="odsce1"
|
|
120
|
+
# style:family="table-cell"
|
|
121
|
+
# style:parent-style-name="Default"
|
|
122
|
+
# style:data-style-name="N0"
|
|
123
|
+
# >
|
|
124
|
+
# <style:table-cell-properties fo:background-color="#ffff00" />
|
|
125
|
+
# <style:text-properties fo:color="#ff0000" />
|
|
126
|
+
# </style:style>
|
|
127
|
+
# </office:automatic-styles>
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
def reference_ods_table_cell_style(
|
|
131
|
+
self, foreground_color: ColorType, background_color: ColorType
|
|
132
|
+
) -> str:
|
|
133
|
+
ods_style = OdsTableCellStyle()
|
|
134
|
+
self._ods_table_cell_style_list.append(ods_style)
|
|
135
|
+
ods_style._xml_ref = "".join(
|
|
136
|
+
["odsce", str(len(self._ods_table_cell_style_list))]
|
|
137
|
+
)
|
|
138
|
+
ods_style._background_color = background_color
|
|
139
|
+
ods_style._text_color = foreground_color
|
|
140
|
+
return ods_style.xml_ref
|
|
141
|
+
|
|
142
|
+
def style_ref(self) -> str:
|
|
143
|
+
style_ref = "ce1"
|
|
144
|
+
if self._current_style_ref is not None:
|
|
145
|
+
style_ref = self._current_style_ref
|
|
146
|
+
self._current_style_ref = None
|
|
147
|
+
return style_ref
|
|
148
|
+
|
|
149
|
+
def set_ods_table_cell_style_reference(self, cell_ref: str):
|
|
150
|
+
"""set the cell table style. This is applied to in the stream to following
|
|
151
|
+
# * cells. This ends by using an other style reference or by using
|
|
152
|
+
# * setTableCellStyleRef function"""
|
|
153
|
+
self._current_style_ref = cell_ref
|
|
154
|
+
|
|
155
|
+
def write_sheet(self, table_name: str):
|
|
156
|
+
self._start_spreadsheet()
|
|
157
|
+
self._write_end_table()
|
|
158
|
+
self._current_sheet_name = table_name
|
|
159
|
+
self._table_started = True
|
|
160
|
+
table_str = '<table:table table:name="{table_name}" table:style-name="ta1" table:print="false">'.format(
|
|
161
|
+
table_name=str_xml_encode(table_name)
|
|
162
|
+
)
|
|
163
|
+
self._zfile.write(table_str.encode())
|
|
164
|
+
table_str = '<table:table-column table:style-name="co1" table:default-cell-style-name="ce1" />'
|
|
165
|
+
self._zfile.write(table_str.encode())
|
|
166
|
+
self._row_pos = 0
|
|
167
|
+
self._col_pos = 0
|
|
168
|
+
|
|
169
|
+
def close(self):
|
|
170
|
+
|
|
171
|
+
# self._write_automatic_styles()
|
|
172
|
+
self._start_spreadsheet()
|
|
173
|
+
self._write_end_table()
|
|
174
|
+
self._zfile.write(
|
|
175
|
+
b"</office:spreadsheet></office:body></office:document-content>"
|
|
176
|
+
)
|
|
177
|
+
self._zfile.close()
|
|
178
|
+
|
|
179
|
+
def _start_spreadsheet(self):
|
|
180
|
+
self._write_automatic_styles()
|
|
181
|
+
if self._spreadsheet_started:
|
|
182
|
+
return
|
|
183
|
+
self._spreadsheet_started = True
|
|
184
|
+
self._zfile.write(b"<office:body><office:spreadsheet>")
|
|
185
|
+
|
|
186
|
+
def _write_end_table(self):
|
|
187
|
+
if self._table_row_started:
|
|
188
|
+
self._zfile.write(b"</table:table-row>")
|
|
189
|
+
if self._table_started:
|
|
190
|
+
self._zfile.write(b"</table:table>")
|
|
191
|
+
# void
|
|
192
|
+
# ContentXml::writeEndTable()
|
|
193
|
+
# {
|
|
194
|
+
# if(_tableRowStarted)
|
|
195
|
+
# {
|
|
196
|
+
# _p_writer->writeEndElement();
|
|
197
|
+
# }
|
|
198
|
+
|
|
199
|
+
# if(_tableStarted)
|
|
200
|
+
# {
|
|
201
|
+
# std::vector<OdsColorScale> sheet_color_scale_list =
|
|
202
|
+
# getOdsColorScaleListBySheetName(_current_sheet_name);
|
|
203
|
+
# if(sheet_color_scale_list.size() > 0)
|
|
204
|
+
# {
|
|
205
|
+
# /*
|
|
206
|
+
# <calcext:conditional-formats>
|
|
207
|
+
# <calcext:conditional-format
|
|
208
|
+
# calcext:target-range-address="classeur.A5:classeur.E6" >
|
|
209
|
+
# <calcext:color-scale>
|
|
210
|
+
# <calcext:color-scale-entry calcext:value="0"
|
|
211
|
+
# calcext:type="minimum" calcext:color="#0000ff"/>
|
|
212
|
+
# <calcext:color-scale-entry calcext:value="50"
|
|
213
|
+
# calcext:type="percentile" calcext:color="#ffffff"/>
|
|
214
|
+
# <calcext:color-scale-entry calcext:value="0"
|
|
215
|
+
# calcext:type="maximum" calcext:color="#ff0000"/>
|
|
216
|
+
# </calcext:color-scale>
|
|
217
|
+
# </calcext:conditional-format>
|
|
218
|
+
# </calcext:conditional-formats>
|
|
219
|
+
# </table:table>*/
|
|
220
|
+
# //<calcext:conditional-formats>
|
|
221
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("calcext"),
|
|
222
|
+
# "conditional-formats");
|
|
223
|
+
|
|
224
|
+
# for(OdsColorScale color_scale : sheet_color_scale_list)
|
|
225
|
+
# {
|
|
226
|
+
# color_scale.writeConditionalFormat(_p_writer);
|
|
227
|
+
# }
|
|
228
|
+
|
|
229
|
+
# //</calcext:conditional-formats>
|
|
230
|
+
# _p_writer->writeEndElement();
|
|
231
|
+
# }
|
|
232
|
+
|
|
233
|
+
# _p_writer->writeEndElement();
|
|
234
|
+
# }
|
|
235
|
+
self._table_started = False
|
|
236
|
+
self._table_row_started = False
|
|
237
|
+
self._row_pos = 0
|
|
238
|
+
self._col_pos = 0
|
|
239
|
+
|
|
240
|
+
def write_line(self):
|
|
241
|
+
|
|
242
|
+
# self._write_automatic_styles()
|
|
243
|
+
self._start_spreadsheet()
|
|
244
|
+
if not self._table_started:
|
|
245
|
+
self.write_sheet("table")
|
|
246
|
+
if self._table_row_started:
|
|
247
|
+
# close current row
|
|
248
|
+
self._zfile.write(b"</table:table-row>")
|
|
249
|
+
self._row_pos = self._row_pos + 1
|
|
250
|
+
self._col_pos = 0
|
|
251
|
+
self._table_row_started = True
|
|
252
|
+
# /*
|
|
253
|
+
# * <table:table-row table:style-name="ro1">
|
|
254
|
+
# */
|
|
255
|
+
self._zfile.write(b'<table:table-row table:style-name="ro1">')
|
|
256
|
+
|
|
257
|
+
def _write_annotation(self, annotation: str | None):
|
|
258
|
+
if annotation is not None:
|
|
259
|
+
text_p = Element("office:annotation")
|
|
260
|
+
# <text:a xlink:href="{the_url}" xlink:type="simple">{the_caption}</text:a>
|
|
261
|
+
text_a = SubElement(text_p, "text:p")
|
|
262
|
+
text_a.text = annotation
|
|
263
|
+
str_text = tostring(text_p, encoding="utf-8").decode("utf-8")
|
|
264
|
+
|
|
265
|
+
self._zfile.write(str_text.encode())
|
|
266
|
+
|
|
267
|
+
# <office:annotation>
|
|
268
|
+
# <text:p>ceci est un commentaire n1</text:p>
|
|
269
|
+
# </office:annotation>
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
def write_cell_percentage(self, value: float, annotation: str | None):
|
|
273
|
+
|
|
274
|
+
# self._write_automatic_styles()
|
|
275
|
+
self._start_spreadsheet()
|
|
276
|
+
if value is None:
|
|
277
|
+
value = ""
|
|
278
|
+
if not self._table_row_started:
|
|
279
|
+
self.write_line()
|
|
280
|
+
|
|
281
|
+
string_representation = f"{value}"
|
|
282
|
+
str_text = '<table:table-cell office:value-type="percentage" office:value="{str_representation}" calcext:value-type="percentage" table:style-name="{style_ref}">'.format(
|
|
283
|
+
str_representation=str_xml_encode(string_representation),
|
|
284
|
+
style_ref=self.style_ref(),
|
|
285
|
+
)
|
|
286
|
+
self._zfile.write(str_text.encode())
|
|
287
|
+
|
|
288
|
+
self._write_annotation(annotation)
|
|
289
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
290
|
+
# _p_writer->writeCharacters(value);
|
|
291
|
+
# <text:p>truc</text:p>
|
|
292
|
+
text_p = Element("text:p")
|
|
293
|
+
text_p.text = string_representation
|
|
294
|
+
str_text = (
|
|
295
|
+
tostring(text_p, encoding="utf-8").decode("utf-8") + "</table:table-cell>"
|
|
296
|
+
)
|
|
297
|
+
self._zfile.write(str_text.encode())
|
|
298
|
+
# _p_writer->writeEndElement();
|
|
299
|
+
|
|
300
|
+
self._col_pos = self._col_pos + 1
|
|
301
|
+
|
|
302
|
+
def write_cell_url(self, the_url: str, caption: str, annotation: str | None):
|
|
303
|
+
# <text:a
|
|
304
|
+
# xlink:href="http://pappso.inra.fr/"
|
|
305
|
+
# xlink:type="simple"
|
|
306
|
+
# >ceci est un lien</text:a>
|
|
307
|
+
|
|
308
|
+
self._start_spreadsheet()
|
|
309
|
+
if not self._table_row_started:
|
|
310
|
+
self.write_line()
|
|
311
|
+
|
|
312
|
+
str_text = '<table:table-cell office:value-type="string" table:style-name="{style_ref}">'.format(
|
|
313
|
+
style_ref=self.style_ref(),
|
|
314
|
+
)
|
|
315
|
+
self._zfile.write(str_text.encode())
|
|
316
|
+
self._write_annotation(annotation)
|
|
317
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
318
|
+
# _p_writer->writeCharacters(value);
|
|
319
|
+
# <text:p>truc</text:p>
|
|
320
|
+
|
|
321
|
+
text_p = Element("text:p")
|
|
322
|
+
# <text:a xlink:href="{the_url}" xlink:type="simple">{the_caption}</text:a>
|
|
323
|
+
text_a = SubElement(text_p, "text:a")
|
|
324
|
+
text_a.attrib["xlink:href"] = the_url
|
|
325
|
+
text_a.attrib["xlink:type"] = "simple"
|
|
326
|
+
text_a.text = caption
|
|
327
|
+
str_text = (
|
|
328
|
+
tostring(text_p, encoding="utf-8").decode("utf-8") + "</table:table-cell>"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
self._zfile.write(str_text.encode())
|
|
332
|
+
|
|
333
|
+
self._col_pos = self._col_pos + 1
|
|
334
|
+
|
|
335
|
+
def write_cell(
|
|
336
|
+
self,
|
|
337
|
+
value: str | int | float | bool | datetime.datetime | datetime.date | None,
|
|
338
|
+
annotation: str | None,
|
|
339
|
+
):
|
|
340
|
+
# self._write_automatic_styles()
|
|
341
|
+
self._start_spreadsheet()
|
|
342
|
+
if value is None:
|
|
343
|
+
value = ""
|
|
344
|
+
if not self._table_row_started:
|
|
345
|
+
self.write_line()
|
|
346
|
+
if isinstance(value, str):
|
|
347
|
+
str_text = '<table:table-cell office:value-type="string" table:style-name="{style_ref}">'.format(
|
|
348
|
+
style_ref=self.style_ref(),
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# print(str_text)
|
|
352
|
+
self._zfile.write(str_text.encode())
|
|
353
|
+
self._write_annotation(annotation)
|
|
354
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
355
|
+
# _p_writer->writeCharacters(value);
|
|
356
|
+
# <text:p>truc</text:p>
|
|
357
|
+
|
|
358
|
+
text_p = Element("text:p")
|
|
359
|
+
text_p.text = value
|
|
360
|
+
str_text = (
|
|
361
|
+
tostring(text_p, encoding="utf-8").decode("utf-8")
|
|
362
|
+
+ "</table:table-cell>"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
self._zfile.write(str_text.encode())
|
|
366
|
+
# _p_writer->writeEndElement();
|
|
367
|
+
|
|
368
|
+
# _p_writer->writeEndElement();
|
|
369
|
+
elif isinstance(value, bool):
|
|
370
|
+
self._write_cell_bool(value, annotation)
|
|
371
|
+
elif isinstance(value, int):
|
|
372
|
+
self._write_cell_number(value, annotation)
|
|
373
|
+
elif isinstance(value, float):
|
|
374
|
+
self._write_cell_number(value, annotation)
|
|
375
|
+
elif isinstance(value, datetime.datetime):
|
|
376
|
+
self._write_cell_date(value, annotation)
|
|
377
|
+
elif isinstance(value, datetime.date):
|
|
378
|
+
self._write_cell_date(value, annotation)
|
|
379
|
+
else:
|
|
380
|
+
pass
|
|
381
|
+
|
|
382
|
+
self._col_pos = self._col_pos + 1
|
|
383
|
+
|
|
384
|
+
def _write_cell_number(self, number: int | float, annotation: str | None):
|
|
385
|
+
|
|
386
|
+
string_representation = f"{number}"
|
|
387
|
+
str_text = '<table:table-cell office:value-type="float" office:value="{str_representation}" table:style-name="{style_ref}">'.format(
|
|
388
|
+
style_ref=self.style_ref(),
|
|
389
|
+
str_representation=str_xml_encode(string_representation),
|
|
390
|
+
)
|
|
391
|
+
self._zfile.write(str_text.encode())
|
|
392
|
+
self._write_annotation(annotation)
|
|
393
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
394
|
+
# _p_writer->writeCharacters(value);
|
|
395
|
+
# <text:p>truc</text:p>
|
|
396
|
+
str_text = "<text:p>{the_value}</text:p></table:table-cell>".format(
|
|
397
|
+
the_value=str_xml_encode(string_representation)
|
|
398
|
+
)
|
|
399
|
+
self._zfile.write(str_text.encode())
|
|
400
|
+
|
|
401
|
+
def _write_cell_bool(self, the_bool: bool, annotation: str | None):
|
|
402
|
+
|
|
403
|
+
# assert the_bool
|
|
404
|
+
string_representation = "false"
|
|
405
|
+
if the_bool:
|
|
406
|
+
string_representation = "true"
|
|
407
|
+
|
|
408
|
+
str_text = '<table:table-cell office:value-type="boolean" office:boolean-value="{str_representation}" table:style-name="{style_ref}">'.format(
|
|
409
|
+
style_ref=self.style_ref(),
|
|
410
|
+
str_representation=string_representation,
|
|
411
|
+
)
|
|
412
|
+
self._zfile.write(str_text.encode())
|
|
413
|
+
self._write_annotation(annotation)
|
|
414
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
415
|
+
# _p_writer->writeCharacters(value);
|
|
416
|
+
# <text:p>truc</text:p>
|
|
417
|
+
str_text = "<text:p>{the_value}</text:p></table:table-cell>".format(
|
|
418
|
+
the_value=string_representation
|
|
419
|
+
)
|
|
420
|
+
self._zfile.write(str_text.encode())
|
|
421
|
+
|
|
422
|
+
def _write_cell_date(
|
|
423
|
+
self, the_date: datetime.datetime | datetime.date, annotation: str | None
|
|
424
|
+
):
|
|
425
|
+
|
|
426
|
+
str_text = '<table:table-cell office:value-type="date" office:date-value="{str_representation}" table:style-name="{style_ref}">'.format(
|
|
427
|
+
style_ref=self.style_ref(),
|
|
428
|
+
str_representation=date_specific_iso(the_date),
|
|
429
|
+
)
|
|
430
|
+
self._zfile.write(str_text.encode())
|
|
431
|
+
self._write_annotation(annotation)
|
|
432
|
+
# _p_writer->writeStartElement(MetaXml::getNamespaceURI("text"), "p");
|
|
433
|
+
# _p_writer->writeCharacters(value);
|
|
434
|
+
# <text:p>truc</text:p>
|
|
435
|
+
str_text = "<text:p>{the_value}</text:p></table:table-cell>".format(
|
|
436
|
+
the_value="-".join(
|
|
437
|
+
[str(the_date.year), str(the_date.month), str(the_date.day)]
|
|
438
|
+
)
|
|
439
|
+
)
|
|
440
|
+
self._zfile.write(str_text.encode())
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
|
2
|
+
<office:document-content
|
|
3
|
+
xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0"
|
|
4
|
+
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
|
|
5
|
+
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
|
|
6
|
+
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
|
|
7
|
+
xmlns:db="urn:oasis:names:tc:opendocument:xmlns:database:1.0"
|
|
8
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
9
|
+
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
|
|
10
|
+
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
|
11
|
+
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
|
12
|
+
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
|
|
13
|
+
xmlns:grddl="http://www.w3.org/2003/g/data-view#"
|
|
14
|
+
xmlns:math="http://www.w3.org/1998/Math/MathML"
|
|
15
|
+
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
|
16
|
+
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
|
17
|
+
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
|
|
18
|
+
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
|
19
|
+
xmlns:ooo="http://openoffice.org/2004/office"
|
|
20
|
+
xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
|
|
21
|
+
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
|
|
22
|
+
xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0"
|
|
23
|
+
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
|
24
|
+
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
|
25
|
+
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
|
26
|
+
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
|
27
|
+
xmlns:xforms="http://www.w3.org/2002/xforms"
|
|
28
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
29
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
30
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
|
31
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
32
|
+
office:version="1.2"
|
|
33
|
+
>
|
|
34
|
+
<office:scripts />
|
|
35
|
+
<office:font-face-decls>
|
|
36
|
+
<style:font-face
|
|
37
|
+
style:font-family-generic="swiss"
|
|
38
|
+
style:font-pitch="variable"
|
|
39
|
+
style:name="Arial"
|
|
40
|
+
svg:font-family="Arial"
|
|
41
|
+
/>
|
|
42
|
+
</office:font-face-decls>
|