New upstream version 0.1.1
Sophie Brun
6 years ago
0 | {%extends 'README.rst.jj2' %} | |
1 | ||
2 | {%block description%} | |
3 | **pyexcel-ods** is a tiny wrapper library to read, manipulate and write data in | |
4 | ods fromat using python 2.6 and python 2.7. You are likely to use it with | |
5 | `pyexcel <https://github.com/pyexcel/pyexcel>`_. | |
6 | `pyexcel-ods3 <https://github.com/pyexcel/pyexcel-ods3>`_ is a sister library that | |
7 | does the same thing but supports Python 3.3 and 3.4 and depends on lxml. | |
8 | {%endblock%} | |
9 | ||
10 | {%block extras %} | |
11 | Credits | |
12 | ================================================================================ | |
13 | ||
14 | ODSReader is originally written by `Marco Conti <https://github.com/marcoconti83/read-ods-with-odfpy>`_ | |
15 | {%endblock%} |
0 | {% extends 'setup.py.jj2' %} | |
1 | ||
2 | {%block additional_classifiers%} | |
3 | 'Programming Language :: Python :: 2.6', | |
4 | 'Programming Language :: Python :: 2.7' | |
5 | {%endblock%}} | |
6 |
0 | {% extends 'tests/requirements.txt.jj2' %} | |
1 | {%block extras %} | |
2 | pyexcel | |
3 | pyexcel-xls | |
4 | {%endblock%} |
0 | sudo: false | |
1 | language: python | |
2 | notifications: | |
3 | email: false | |
4 | env: | |
5 | global: | |
6 | python: | |
7 | - 2.7 | |
8 | - 2.6 | |
9 | install: | |
10 | - rm applymoban.py | |
11 | - pip install -r requirements.txt | |
12 | - pip install -r tests/requirements.txt | |
13 | script: | |
14 | make test | |
15 | after_success: | |
16 | codecov⏎ |
0 | Copyright (c) 2015-2016 by Onni Software Ltd. and its contributors | |
1 | All rights reserved. | |
2 | ||
3 | Redistribution and use in source and binary forms of the software as well | |
4 | as documentation, with or without modification, are permitted provided | |
5 | that the following conditions are met: | |
6 | ||
7 | * Redistributions of source code must retain the above copyright notice, this | |
8 | list of conditions and the following disclaimer. | |
9 | ||
10 | * Redistributions in binary form must reproduce the above copyright notice, | |
11 | this list of conditions and the following disclaimer in the documentation | |
12 | and/or other materials provided with the distribution. | |
13 | ||
14 | * Neither the name of 'pyexcel-ods' nor the names of the contributors | |
15 | may not be used to endorse or promote products derived from this software | |
16 | without specific prior written permission. | |
17 | ||
18 | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |
19 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT | |
20 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | |
22 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
28 | SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
29 | DAMAGE.⏎ |
0 | include README.rst |
0 | ================================================================================ | |
1 | pyexcel-ods - Let you focus on data, instead of ods format | |
2 | ================================================================================ | |
3 | ||
4 | .. image:: https://api.travis-ci.org/pyexcel/pyexcel-ods.png | |
5 | :target: http://travis-ci.org/pyexcel/pyexcel-ods | |
6 | ||
7 | .. image:: https://codecov.io/github/pyexcel/pyexcel-ods/coverage.png | |
8 | :target: https://codecov.io/github/pyexcel/pyexcel-ods | |
9 | ||
10 | **pyexcel-ods** is a tiny wrapper library to read, manipulate and write data in | |
11 | ods fromat using python 2.6 and python 2.7. You are likely to use it with | |
12 | `pyexcel <https://github.com/pyexcel/pyexcel>`_. | |
13 | `pyexcel-ods3 <https://github.com/pyexcel/pyexcel-ods3>`_ is a sister library that | |
14 | does the same thing but supports Python 3.3 and 3.4 and depends on lxml. | |
15 | ||
16 | Known constraints | |
17 | ================================================================================ | |
18 | ||
19 | Fonts, colors and charts are not supported. | |
20 | ||
21 | Installation | |
22 | ================================================================================ | |
23 | ||
24 | You can install it via pip: | |
25 | ||
26 | .. code-block:: bash | |
27 | ||
28 | $ pip install pyexcel-ods | |
29 | ||
30 | or clone it and install it: | |
31 | ||
32 | .. code-block:: bash | |
33 | ||
34 | $ git clone http://github.com/pyexcel/pyexcel-ods.git | |
35 | $ cd pyexcel-ods | |
36 | $ python setup.py install | |
37 | ||
38 | Usage | |
39 | ================================================================================ | |
40 | ||
41 | New feature | |
42 | -------------------------------------------------------------------------------- | |
43 | ||
44 | ||
45 | 1. Passing "streaming=True" to get_data, you will get the two dimensional array as a generator | |
46 | 2. Passing "data=your_generator" to save_data is acceptable too. | |
47 | ||
48 | ||
49 | As a standalone library | |
50 | -------------------------------------------------------------------------------- | |
51 | ||
52 | Write to an ods file | |
53 | ******************************************************************************** | |
54 | ||
55 | .. testcode:: | |
56 | :hide: | |
57 | ||
58 | >>> import sys | |
59 | >>> if sys.version_info[0] < 3: | |
60 | ... from StringIO import StringIO | |
61 | ... else: | |
62 | ... from io import BytesIO as StringIO | |
63 | >>> from pyexcel_io import OrderedDict | |
64 | ||
65 | ||
66 | Here's the sample code to write a dictionary to an ods file: | |
67 | ||
68 | .. code-block:: python | |
69 | ||
70 | >>> from pyexcel_ods import save_data | |
71 | >>> data = OrderedDict() # from collections import OrderedDict | |
72 | >>> data.update({"Sheet 1": [[1, 2, 3], [4, 5, 6]]}) | |
73 | >>> data.update({"Sheet 2": [["row 1", "row 2", "row 3"]]}) | |
74 | >>> save_data("your_file.ods", data) | |
75 | ||
76 | Read from an ods file | |
77 | ******************************************************************************** | |
78 | ||
79 | Here's the sample code: | |
80 | ||
81 | .. code-block:: python | |
82 | ||
83 | >>> from pyexcel_ods import get_data | |
84 | >>> data = get_data("your_file.ods") | |
85 | >>> import json | |
86 | >>> print(json.dumps(data)) | |
87 | {"Sheet 1": [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], "Sheet 2": [["row 1", "row 2", "row 3"]]} | |
88 | ||
89 | Write an ods to memory | |
90 | ******************************************************************************** | |
91 | ||
92 | Here's the sample code to write a dictionary to an ods file: | |
93 | ||
94 | .. code-block:: python | |
95 | ||
96 | >>> from pyexcel_ods import save_data | |
97 | >>> data = OrderedDict() | |
98 | >>> data.update({"Sheet 1": [[1, 2, 3], [4, 5, 6]]}) | |
99 | >>> data.update({"Sheet 2": [[7, 8, 9], [10, 11, 12]]}) | |
100 | >>> io = StringIO() | |
101 | >>> save_data(io, data) | |
102 | >>> # do something with the io | |
103 | >>> # In reality, you might give it to your http response | |
104 | >>> # object for downloading | |
105 | ||
106 | ||
107 | ||
108 | Read from an ods from memory | |
109 | ******************************************************************************** | |
110 | ||
111 | Continue from previous example: | |
112 | ||
113 | .. code-block:: python | |
114 | ||
115 | >>> # This is just an illustration | |
116 | >>> # In reality, you might deal with ods file upload | |
117 | >>> # where you will read from requests.FILES['YOUR_ODS_FILE'] | |
118 | >>> data = get_data(io) | |
119 | >>> print(json.dumps(data)) | |
120 | {"Sheet 1": [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], "Sheet 2": [[7.0, 8.0, 9.0], [10.0, 11.0, 12.0]]} | |
121 | ||
122 | ||
123 | As a pyexcel plugin | |
124 | -------------------------------------------------------------------------------- | |
125 | ||
126 | Import it in your file to enable this plugin: | |
127 | ||
128 | .. code-block:: python | |
129 | ||
130 | from pyexcel.ext import ods | |
131 | ||
132 | Please note only pyexcel version 0.0.4+ support this. | |
133 | ||
134 | Reading from an ods file | |
135 | ******************************************************************************** | |
136 | ||
137 | Here is the sample code: | |
138 | ||
139 | .. code-block:: python | |
140 | ||
141 | >>> import pyexcel as pe | |
142 | >>> from pyexcel.ext import ods | |
143 | >>> sheet = pe.get_book(file_name="your_file.ods") | |
144 | >>> sheet | |
145 | Sheet Name: Sheet 1 | |
146 | +---+---+---+ | |
147 | | 1 | 2 | 3 | | |
148 | +---+---+---+ | |
149 | | 4 | 5 | 6 | | |
150 | +---+---+---+ | |
151 | Sheet Name: Sheet 2 | |
152 | +-------+-------+-------+ | |
153 | | row 1 | row 2 | row 3 | | |
154 | +-------+-------+-------+ | |
155 | ||
156 | Writing to an ods file | |
157 | ******************************************************************************** | |
158 | ||
159 | Here is the sample code: | |
160 | ||
161 | .. code-block:: python | |
162 | ||
163 | >>> sheet.save_as("another_file.ods") | |
164 | ||
165 | Reading from a IO instance | |
166 | ================================================================================ | |
167 | ||
168 | You got to wrap the binary content with stream to get ods working: | |
169 | ||
170 | .. code-block:: python | |
171 | ||
172 | >>> # This is just an illustration | |
173 | >>> # In reality, you might deal with ods file upload | |
174 | >>> # where you will read from requests.FILES['YOUR_ODS_FILE'] | |
175 | >>> odsfile = "another_file.ods" | |
176 | >>> with open(odsfile, "rb") as f: | |
177 | ... content = f.read() | |
178 | ... r = pe.get_book(file_type="ods", file_content=content) | |
179 | ... print(r) | |
180 | ... | |
181 | Sheet Name: Sheet 1 | |
182 | +---+---+---+ | |
183 | | 1 | 2 | 3 | | |
184 | +---+---+---+ | |
185 | | 4 | 5 | 6 | | |
186 | +---+---+---+ | |
187 | Sheet Name: Sheet 2 | |
188 | +-------+-------+-------+ | |
189 | | row 1 | row 2 | row 3 | | |
190 | +-------+-------+-------+ | |
191 | ||
192 | ||
193 | Writing to a StringIO instance | |
194 | ================================================================================ | |
195 | ||
196 | You need to pass a StringIO instance to Writer: | |
197 | ||
198 | .. code-block:: python | |
199 | ||
200 | >>> data = [ | |
201 | ... [1, 2, 3], | |
202 | ... [4, 5, 6] | |
203 | ... ] | |
204 | >>> io = StringIO() | |
205 | >>> sheet = pe.Sheet(data) | |
206 | >>> sheet.save_to_memory("ods", io) | |
207 | >>> # then do something with io | |
208 | >>> # In reality, you might give it to your http response | |
209 | >>> # object for downloading | |
210 | ||
211 | License | |
212 | ================================================================================ | |
213 | ||
214 | New BSD License | |
215 | ||
216 | Credits | |
217 | ================================================================================ | |
218 | ||
219 | ODSReader is originally written by `Marco Conti <https://github.com/marcoconti83/read-ods-with-odfpy>`_ | |
220 | ||
221 | .. testcode:: | |
222 | :hide: | |
223 | ||
224 | >>> import os | |
225 | >>> os.unlink("your_file.ods") | |
226 | >>> os.unlink("another_file.ods")⏎ |
0 | from os import path, system | |
1 | ||
2 | config_dir = 'commons/config' | |
3 | template_dir = 'commons/templates' | |
4 | ||
5 | if not path.exists("commons"): | |
6 | system("git clone https://github.com/pyexcel/pyexcel-commons.git commons") | |
7 | system("moban -cd {0} -td {1} -t docs/source/conf.py.jj2 -o docs/source/conf.py -c moban.yaml".format(config_dir, template_dir)) | |
8 | system("moban -cd {0} -td {1} .moban.d -t README.rst -o README.rst -c moban.yaml".format(config_dir, template_dir)) | |
9 | system("moban -cd {0} -td {1} .moban.d -t setup.py -o setup.py -c moban.yaml".format(config_dir, template_dir)) | |
10 | system("moban -cd {0} -td {1} .moban.d -t travis.yml -o .travis.yml -c moban.yaml".format(config_dir, template_dir)) | |
11 | system("moban -cd {0} -td .moban.d -t requirements.txt -o requirements.txt -c moban.yaml".format(config_dir)) | |
12 | system("moban -cd {0} -td {1} -t LICENSE.jj2 -o LICENSE -c moban.yaml".format(config_dir, template_dir)) | |
13 | system("moban -cd {0} -td {1} .moban.d -t tests/requirements.txt -o tests/requirements.txt -c moban.yaml".format(config_dir, template_dir)) | |
14 | system("moban -cd {0} -td {1} .moban.d -t MANIFEST.in.jj2 -o MANIFEST.in -c moban.yaml".format(config_dir, template_dir)) |
0 | # Makefile for Sphinx documentation | |
1 | # | |
2 | ||
3 | # You can set these variables from the command line. | |
4 | SPHINXOPTS = | |
5 | SPHINXBUILD = sphinx-build | |
6 | PAPER = | |
7 | BUILDDIR = build | |
8 | ||
9 | # User-friendly check for sphinx-build | |
10 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) | |
11 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) | |
12 | endif | |
13 | ||
14 | # Internal variables. | |
15 | PAPEROPT_a4 = -D latex_paper_size=a4 | |
16 | PAPEROPT_letter = -D latex_paper_size=letter | |
17 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source | |
18 | # the i18n builder cannot share the environment and doctrees with the others | |
19 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source | |
20 | ||
21 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext | |
22 | ||
23 | help: | |
24 | @echo "Please use \`make <target>' where <target> is one of" | |
25 | @echo " html to make standalone HTML files" | |
26 | @echo " dirhtml to make HTML files named index.html in directories" | |
27 | @echo " singlehtml to make a single large HTML file" | |
28 | @echo " pickle to make pickle files" | |
29 | @echo " json to make JSON files" | |
30 | @echo " htmlhelp to make HTML files and a HTML help project" | |
31 | @echo " qthelp to make HTML files and a qthelp project" | |
32 | @echo " devhelp to make HTML files and a Devhelp project" | |
33 | @echo " epub to make an epub" | |
34 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" | |
35 | @echo " latexpdf to make LaTeX files and run them through pdflatex" | |
36 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" | |
37 | @echo " text to make text files" | |
38 | @echo " man to make manual pages" | |
39 | @echo " texinfo to make Texinfo files" | |
40 | @echo " info to make Texinfo files and run them through makeinfo" | |
41 | @echo " gettext to make PO message catalogs" | |
42 | @echo " changes to make an overview of all changed/added/deprecated items" | |
43 | @echo " xml to make Docutils-native XML files" | |
44 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" | |
45 | @echo " linkcheck to check all external links for integrity" | |
46 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" | |
47 | ||
48 | clean: | |
49 | rm -rf $(BUILDDIR)/* | |
50 | ||
51 | html: | |
52 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html | |
53 | @echo | |
54 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." | |
55 | ||
56 | dirhtml: | |
57 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml | |
58 | @echo | |
59 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." | |
60 | ||
61 | singlehtml: | |
62 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml | |
63 | @echo | |
64 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." | |
65 | ||
66 | pickle: | |
67 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle | |
68 | @echo | |
69 | @echo "Build finished; now you can process the pickle files." | |
70 | ||
71 | json: | |
72 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json | |
73 | @echo | |
74 | @echo "Build finished; now you can process the JSON files." | |
75 | ||
76 | htmlhelp: | |
77 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp | |
78 | @echo | |
79 | @echo "Build finished; now you can run HTML Help Workshop with the" \ | |
80 | ".hhp project file in $(BUILDDIR)/htmlhelp." | |
81 | ||
82 | qthelp: | |
83 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp | |
84 | @echo | |
85 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ | |
86 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | |
87 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyexcel-ods.qhcp" | |
88 | @echo "To view the help file:" | |
89 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyexcel-ods.qhc" | |
90 | ||
91 | devhelp: | |
92 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | |
93 | @echo | |
94 | @echo "Build finished." | |
95 | @echo "To view the help file:" | |
96 | @echo "# mkdir -p $$HOME/.local/share/devhelp/pyexcel-ods" | |
97 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyexcel-ods" | |
98 | @echo "# devhelp" | |
99 | ||
100 | epub: | |
101 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub | |
102 | @echo | |
103 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." | |
104 | ||
105 | latex: | |
106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
107 | @echo | |
108 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." | |
109 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ | |
110 | "(use \`make latexpdf' here to do that automatically)." | |
111 | ||
112 | latexpdf: | |
113 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
114 | @echo "Running LaTeX files through pdflatex..." | |
115 | $(MAKE) -C $(BUILDDIR)/latex all-pdf | |
116 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |
117 | ||
118 | latexpdfja: | |
119 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
120 | @echo "Running LaTeX files through platex and dvipdfmx..." | |
121 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja | |
122 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |
123 | ||
124 | text: | |
125 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text | |
126 | @echo | |
127 | @echo "Build finished. The text files are in $(BUILDDIR)/text." | |
128 | ||
129 | man: | |
130 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man | |
131 | @echo | |
132 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." | |
133 | ||
134 | texinfo: | |
135 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |
136 | @echo | |
137 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." | |
138 | @echo "Run \`make' in that directory to run these through makeinfo" \ | |
139 | "(use \`make info' here to do that automatically)." | |
140 | ||
141 | info: | |
142 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo | |
143 | @echo "Running Texinfo files through makeinfo..." | |
144 | make -C $(BUILDDIR)/texinfo info | |
145 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." | |
146 | ||
147 | gettext: | |
148 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale | |
149 | @echo | |
150 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." | |
151 | ||
152 | changes: | |
153 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes | |
154 | @echo | |
155 | @echo "The overview file is in $(BUILDDIR)/changes." | |
156 | ||
157 | linkcheck: | |
158 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | |
159 | @echo | |
160 | @echo "Link check complete; look for any errors in the above output " \ | |
161 | "or in $(BUILDDIR)/linkcheck/output.txt." | |
162 | ||
163 | doctest: | |
164 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest | |
165 | @echo "Testing of doctests in the sources finished, look at the " \ | |
166 | "results in $(BUILDDIR)/doctest/output.txt." | |
167 | ||
168 | xml: | |
169 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml | |
170 | @echo | |
171 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." | |
172 | ||
173 | pseudoxml: | |
174 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml | |
175 | @echo | |
176 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." |
0 | @ECHO OFF | |
1 | ||
2 | REM Command file for Sphinx documentation | |
3 | ||
4 | if "%SPHINXBUILD%" == "" ( | |
5 | set SPHINXBUILD=sphinx-build | |
6 | ) | |
7 | set BUILDDIR=build | |
8 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source | |
9 | set I18NSPHINXOPTS=%SPHINXOPTS% source | |
10 | if NOT "%PAPER%" == "" ( | |
11 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% | |
12 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% | |
13 | ) | |
14 | ||
15 | if "%1" == "" goto help | |
16 | ||
17 | if "%1" == "help" ( | |
18 | :help | |
19 | echo.Please use `make ^<target^>` where ^<target^> is one of | |
20 | echo. html to make standalone HTML files | |
21 | echo. dirhtml to make HTML files named index.html in directories | |
22 | echo. singlehtml to make a single large HTML file | |
23 | echo. pickle to make pickle files | |
24 | echo. json to make JSON files | |
25 | echo. htmlhelp to make HTML files and a HTML help project | |
26 | echo. qthelp to make HTML files and a qthelp project | |
27 | echo. devhelp to make HTML files and a Devhelp project | |
28 | echo. epub to make an epub | |
29 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter | |
30 | echo. text to make text files | |
31 | echo. man to make manual pages | |
32 | echo. texinfo to make Texinfo files | |
33 | echo. gettext to make PO message catalogs | |
34 | echo. changes to make an overview over all changed/added/deprecated items | |
35 | echo. xml to make Docutils-native XML files | |
36 | echo. pseudoxml to make pseudoxml-XML files for display purposes | |
37 | echo. linkcheck to check all external links for integrity | |
38 | echo. doctest to run all doctests embedded in the documentation if enabled | |
39 | goto end | |
40 | ) | |
41 | ||
42 | if "%1" == "clean" ( | |
43 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i | |
44 | del /q /s %BUILDDIR%\* | |
45 | goto end | |
46 | ) | |
47 | ||
48 | ||
49 | %SPHINXBUILD% 2> nul | |
50 | if errorlevel 9009 ( | |
51 | echo. | |
52 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | |
53 | echo.installed, then set the SPHINXBUILD environment variable to point | |
54 | echo.to the full path of the 'sphinx-build' executable. Alternatively you | |
55 | echo.may add the Sphinx directory to PATH. | |
56 | echo. | |
57 | echo.If you don't have Sphinx installed, grab it from | |
58 | echo.http://sphinx-doc.org/ | |
59 | exit /b 1 | |
60 | ) | |
61 | ||
62 | if "%1" == "html" ( | |
63 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html | |
64 | if errorlevel 1 exit /b 1 | |
65 | echo. | |
66 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. | |
67 | goto end | |
68 | ) | |
69 | ||
70 | if "%1" == "dirhtml" ( | |
71 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml | |
72 | if errorlevel 1 exit /b 1 | |
73 | echo. | |
74 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. | |
75 | goto end | |
76 | ) | |
77 | ||
78 | if "%1" == "singlehtml" ( | |
79 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml | |
80 | if errorlevel 1 exit /b 1 | |
81 | echo. | |
82 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. | |
83 | goto end | |
84 | ) | |
85 | ||
86 | if "%1" == "pickle" ( | |
87 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle | |
88 | if errorlevel 1 exit /b 1 | |
89 | echo. | |
90 | echo.Build finished; now you can process the pickle files. | |
91 | goto end | |
92 | ) | |
93 | ||
94 | if "%1" == "json" ( | |
95 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json | |
96 | if errorlevel 1 exit /b 1 | |
97 | echo. | |
98 | echo.Build finished; now you can process the JSON files. | |
99 | goto end | |
100 | ) | |
101 | ||
102 | if "%1" == "htmlhelp" ( | |
103 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp | |
104 | if errorlevel 1 exit /b 1 | |
105 | echo. | |
106 | echo.Build finished; now you can run HTML Help Workshop with the ^ | |
107 | .hhp project file in %BUILDDIR%/htmlhelp. | |
108 | goto end | |
109 | ) | |
110 | ||
111 | if "%1" == "qthelp" ( | |
112 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp | |
113 | if errorlevel 1 exit /b 1 | |
114 | echo. | |
115 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ | |
116 | .qhcp project file in %BUILDDIR%/qthelp, like this: | |
117 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyexcel-ods.qhcp | |
118 | echo.To view the help file: | |
119 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyexcel-ods.ghc | |
120 | goto end | |
121 | ) | |
122 | ||
123 | if "%1" == "devhelp" ( | |
124 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp | |
125 | if errorlevel 1 exit /b 1 | |
126 | echo. | |
127 | echo.Build finished. | |
128 | goto end | |
129 | ) | |
130 | ||
131 | if "%1" == "epub" ( | |
132 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub | |
133 | if errorlevel 1 exit /b 1 | |
134 | echo. | |
135 | echo.Build finished. The epub file is in %BUILDDIR%/epub. | |
136 | goto end | |
137 | ) | |
138 | ||
139 | if "%1" == "latex" ( | |
140 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex | |
141 | if errorlevel 1 exit /b 1 | |
142 | echo. | |
143 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. | |
144 | goto end | |
145 | ) | |
146 | ||
147 | if "%1" == "latexpdf" ( | |
148 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex | |
149 | cd %BUILDDIR%/latex | |
150 | make all-pdf | |
151 | cd %BUILDDIR%/.. | |
152 | echo. | |
153 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. | |
154 | goto end | |
155 | ) | |
156 | ||
157 | if "%1" == "latexpdfja" ( | |
158 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex | |
159 | cd %BUILDDIR%/latex | |
160 | make all-pdf-ja | |
161 | cd %BUILDDIR%/.. | |
162 | echo. | |
163 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. | |
164 | goto end | |
165 | ) | |
166 | ||
167 | if "%1" == "text" ( | |
168 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text | |
169 | if errorlevel 1 exit /b 1 | |
170 | echo. | |
171 | echo.Build finished. The text files are in %BUILDDIR%/text. | |
172 | goto end | |
173 | ) | |
174 | ||
175 | if "%1" == "man" ( | |
176 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man | |
177 | if errorlevel 1 exit /b 1 | |
178 | echo. | |
179 | echo.Build finished. The manual pages are in %BUILDDIR%/man. | |
180 | goto end | |
181 | ) | |
182 | ||
183 | if "%1" == "texinfo" ( | |
184 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo | |
185 | if errorlevel 1 exit /b 1 | |
186 | echo. | |
187 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. | |
188 | goto end | |
189 | ) | |
190 | ||
191 | if "%1" == "gettext" ( | |
192 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale | |
193 | if errorlevel 1 exit /b 1 | |
194 | echo. | |
195 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. | |
196 | goto end | |
197 | ) | |
198 | ||
199 | if "%1" == "changes" ( | |
200 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes | |
201 | if errorlevel 1 exit /b 1 | |
202 | echo. | |
203 | echo.The overview file is in %BUILDDIR%/changes. | |
204 | goto end | |
205 | ) | |
206 | ||
207 | if "%1" == "linkcheck" ( | |
208 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck | |
209 | if errorlevel 1 exit /b 1 | |
210 | echo. | |
211 | echo.Link check complete; look for any errors in the above output ^ | |
212 | or in %BUILDDIR%/linkcheck/output.txt. | |
213 | goto end | |
214 | ) | |
215 | ||
216 | if "%1" == "doctest" ( | |
217 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest | |
218 | if errorlevel 1 exit /b 1 | |
219 | echo. | |
220 | echo.Testing of doctests in the sources finished, look at the ^ | |
221 | results in %BUILDDIR%/doctest/output.txt. | |
222 | goto end | |
223 | ) | |
224 | ||
225 | if "%1" == "xml" ( | |
226 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml | |
227 | if errorlevel 1 exit /b 1 | |
228 | echo. | |
229 | echo.Build finished. The XML files are in %BUILDDIR%/xml. | |
230 | goto end | |
231 | ) | |
232 | ||
233 | if "%1" == "pseudoxml" ( | |
234 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml | |
235 | if errorlevel 1 exit /b 1 | |
236 | echo. | |
237 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. | |
238 | goto end | |
239 | ) | |
240 | ||
241 | :end |
0 | # -*- coding: utf-8 -*- | |
1 | import sys | |
2 | import os | |
3 | ||
4 | # If extensions (or modules to document with autodoc) are in another directory, | |
5 | # add these directories to sys.path here. If the directory is relative to the | |
6 | # documentation root, use os.path.abspath to make it absolute, like shown here. | |
7 | #sys.path.insert(0, os.path.abspath('.')) | |
8 | ||
9 | # -- General configuration ------------------------------------------------ | |
10 | ||
11 | # If your documentation needs a minimal Sphinx version, state it here. | |
12 | #needs_sphinx = '1.0' | |
13 | ||
14 | # Add any Sphinx extension module names here, as strings. They can be | |
15 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | |
16 | # ones. | |
17 | extensions = [ | |
18 | 'sphinx.ext.autodoc', | |
19 | 'sphinx.ext.doctest', | |
20 | 'sphinx.ext.intersphinx', | |
21 | 'sphinx.ext.viewcode', | |
22 | ] | |
23 | ||
24 | intersphinx_mapping = {'pyexcel': ('http://pyexcel.readthedocs.org/en/latest/', None)} | |
25 | ||
26 | # Add any paths that contain templates here, relative to this directory. | |
27 | templates_path = ['_templates'] | |
28 | ||
29 | # The suffix of source filenames. | |
30 | source_suffix = '.rst' | |
31 | ||
32 | # The encoding of source files. | |
33 | #source_encoding = 'utf-8-sig' | |
34 | ||
35 | # The master toctree document. | |
36 | master_doc = 'index' | |
37 | ||
38 | # General information about the project. | |
39 | project = u'pyexcel-ods' | |
40 | copyright = u'2015-2016 Onni Software Ltd.' | |
41 | ||
42 | # The version info for the project you're documenting, acts as replacement for | |
43 | # |version| and |release|, also used in various other places throughout the | |
44 | # built documents. | |
45 | # | |
46 | # The short X.Y version. | |
47 | version = '0.1.0' | |
48 | # The full version, including alpha/beta/rc tags. | |
49 | release = '0.1.0' | |
50 | ||
51 | # The language for content autogenerated by Sphinx. Refer to documentation | |
52 | # for a list of supported languages. | |
53 | #language = None | |
54 | ||
55 | # There are two options for replacing |today|: either, you set today to some | |
56 | # non-false value, then it is used: | |
57 | #today = '' | |
58 | # Else, today_fmt is used as the format for a strftime call. | |
59 | #today_fmt = '%B %d, %Y' | |
60 | ||
61 | # List of patterns, relative to source directory, that match files and | |
62 | # directories to ignore when looking for source files. | |
63 | exclude_patterns = [] | |
64 | ||
65 | # The reST default role (used for this markup: `text`) to use for all | |
66 | # documents. | |
67 | #default_role = None | |
68 | ||
69 | # If true, '()' will be appended to :func: etc. cross-reference text. | |
70 | #add_function_parentheses = True | |
71 | ||
72 | # If true, the current module name will be prepended to all description | |
73 | # unit titles (such as .. function::). | |
74 | #add_module_names = True | |
75 | ||
76 | # If true, sectionauthor and moduleauthor directives will be shown in the | |
77 | # output. They are ignored by default. | |
78 | #show_authors = False | |
79 | ||
80 | # The name of the Pygments (syntax highlighting) style to use. | |
81 | pygments_style = 'sphinx' | |
82 | ||
83 | # A list of ignored prefixes for module index sorting. | |
84 | #modindex_common_prefix = [] | |
85 | ||
86 | # If true, keep warnings as "system message" paragraphs in the built documents. | |
87 | #keep_warnings = False | |
88 | ||
89 | ||
90 | # -- Options for HTML output ---------------------------------------------- | |
91 | ||
92 | # The theme to use for HTML and HTML Help pages. See the documentation for | |
93 | # a list of builtin themes. | |
94 | html_theme = 'default' | |
95 | ||
96 | # Theme options are theme-specific and customize the look and feel of a theme | |
97 | # further. For a list of options available for each theme, see the | |
98 | # documentation. | |
99 | #html_theme_options = {} | |
100 | # Add any paths that contain custom themes here, relative to this directory. | |
101 | #html_theme_path = [] | |
102 | ||
103 | # The name for this set of Sphinx documents. If None, it defaults to | |
104 | # "<project> v<release> documentation". | |
105 | #html_title = None | |
106 | ||
107 | # A shorter title for the navigation bar. Default is the same as html_title. | |
108 | #html_short_title = None | |
109 | ||
110 | # The name of an image file (relative to this directory) to place at the top | |
111 | # of the sidebar. | |
112 | #html_logo = None | |
113 | ||
114 | # The name of an image file (within the static path) to use as favicon of the | |
115 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | |
116 | # pixels large. | |
117 | #html_favicon = None | |
118 | ||
119 | # Add any paths that contain custom static files (such as style sheets) here, | |
120 | # relative to this directory. They are copied after the builtin static files, | |
121 | # so a file named "default.css" will overwrite the builtin "default.css". | |
122 | html_static_path = ['_static'] | |
123 | ||
124 | # Add any extra paths that contain custom files (such as robots.txt or | |
125 | # .htaccess) here, relative to this directory. These files are copied | |
126 | # directly to the root of the documentation. | |
127 | #html_extra_path = [] | |
128 | ||
129 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | |
130 | # using the given strftime format. | |
131 | #html_last_updated_fmt = '%b %d, %Y' | |
132 | ||
133 | # If true, SmartyPants will be used to convert quotes and dashes to | |
134 | # typographically correct entities. | |
135 | #html_use_smartypants = True | |
136 | ||
137 | # Custom sidebar templates, maps document names to template names. | |
138 | #html_sidebars = {} | |
139 | ||
140 | # Additional templates that should be rendered to pages, maps page names to | |
141 | # template names. | |
142 | #html_additional_pages = {} | |
143 | ||
144 | # If false, no module index is generated. | |
145 | #html_domain_indices = True | |
146 | ||
147 | # If false, no index is generated. | |
148 | #html_use_index = True | |
149 | ||
150 | # If true, the index is split into individual pages for each letter. | |
151 | #html_split_index = False | |
152 | ||
153 | # If true, links to the reST sources are added to the pages. | |
154 | #html_show_sourcelink = True | |
155 | ||
156 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | |
157 | #html_show_sphinx = True | |
158 | ||
159 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | |
160 | #html_show_copyright = True | |
161 | ||
162 | # If true, an OpenSearch description file will be output, and all pages will | |
163 | # contain a <link> tag referring to it. The value of this option must be the | |
164 | # base URL from which the finished HTML is served. | |
165 | #html_use_opensearch = '' | |
166 | ||
167 | # This is the file name suffix for HTML files (e.g. ".xhtml"). | |
168 | #html_file_suffix = None | |
169 | ||
170 | # Output file base name for HTML help builder. | |
171 | htmlhelp_basename = 'pyexcel-odsdoc' | |
172 | ||
173 | ||
174 | # -- Options for LaTeX output --------------------------------------------- | |
175 | ||
176 | latex_elements = { | |
177 | # The paper size ('letterpaper' or 'a4paper'). | |
178 | #'papersize': 'letterpaper', | |
179 | ||
180 | # The font size ('10pt', '11pt' or '12pt'). | |
181 | #'pointsize': '10pt', | |
182 | ||
183 | # Additional stuff for the LaTeX preamble. | |
184 | #'preamble': '', | |
185 | } | |
186 | ||
187 | # Grouping the document tree into LaTeX files. List of tuples | |
188 | # (source start file, target name, title, | |
189 | # author, documentclass [howto, manual, or own class]). | |
190 | latex_documents = [ | |
191 | ('index', 'pyexcel-ods.tex', u'pyexcel-ods Documentation', | |
192 | u'Onni Software Ltd.', 'manual'), | |
193 | ] | |
194 | ||
195 | # The name of an image file (relative to this directory) to place at the top of | |
196 | # the title page. | |
197 | #latex_logo = None | |
198 | ||
199 | # For "manual" documents, if this is true, then toplevel headings are parts, | |
200 | # not chapters. | |
201 | #latex_use_parts = False | |
202 | ||
203 | # If true, show page references after internal links. | |
204 | #latex_show_pagerefs = False | |
205 | ||
206 | # If true, show URL addresses after external links. | |
207 | #latex_show_urls = False | |
208 | ||
209 | # Documents to append as an appendix to all manuals. | |
210 | #latex_appendices = [] | |
211 | ||
212 | # If false, no module index is generated. | |
213 | #latex_domain_indices = True | |
214 | ||
215 | ||
216 | # -- Options for manual page output --------------------------------------- | |
217 | ||
218 | # One entry per manual page. List of tuples | |
219 | # (source start file, name, description, authors, manual section). | |
220 | man_pages = [ | |
221 | ('index', 'pyexcel-ods', u'pyexcel-ods Documentation', | |
222 | [u'Onni Software Ltd.'], 1) | |
223 | ] | |
224 | ||
225 | # If true, show URL addresses after external links. | |
226 | #man_show_urls = False | |
227 | ||
228 | ||
229 | # -- Options for Texinfo output ------------------------------------------- | |
230 | ||
231 | # Grouping the document tree into Texinfo files. List of tuples | |
232 | # (source start file, target name, title, author, | |
233 | # dir menu entry, description, category) | |
234 | texinfo_documents = [ | |
235 | ('index', 'pyexcel-ods', u'pyexcel-ods Documentation', | |
236 | u'Onni Software Ltd.', 'pyexcel-ods', 'One line description of project.', | |
237 | 'Miscellaneous'), | |
238 | ] | |
239 | ||
240 | # Documents to append as an appendix to all manuals. | |
241 | #texinfo_appendices = [] | |
242 | ||
243 | # If false, no module index is generated. | |
244 | #texinfo_domain_indices = True | |
245 | ||
246 | # How to display URL addresses: 'footnote', 'no', or 'inline'. | |
247 | #texinfo_show_urls = 'footnote' | |
248 | ||
249 | # If true, do not generate a @detailmenu in the "Top" node's menu. | |
250 | #texinfo_no_detailmenu = False⏎ |
0 | .. pyexcel-ods documentation master file, created by | |
1 | sphinx-quickstart on Tue Sep 08 23:32:58 2015. | |
2 | You can adapt this file completely to your liking, but it should at least | |
3 | contain the root `toctree` directive. | |
4 | ||
5 | .. include:: ../../README.rst | |
6 | ||
7 | Indices and tables | |
8 | ================== | |
9 | ||
10 | * :ref:`genindex` | |
11 | * :ref:`modindex` | |
12 | * :ref:`search` | |
13 |
0 | overrides: "pyexcel.yaml" | |
1 | name: "pyexcel-ods" | |
2 | nick_name: ods | |
3 | version: 0.1.0 | |
4 | file_type: ods | |
5 | keywords: | |
6 | - 'ods' | |
7 | dependencies: | |
8 | - pyexcel-io>=0.1.0 | |
9 | - odfpy==0.9.6 | |
10 | description: | | |
11 | A wrapper library to read, manipulate and write data in ods format⏎ |
0 | """ | |
1 | pyexcel_ods | |
2 | ~~~~~~~~~~~~~~~~~~~ | |
3 | ||
4 | ODS format plugin for pyexcel | |
5 | ||
6 | :copyright: (c) 2015-2016 by Onni Software Ltd. | |
7 | :license: New BSD License, see LICENSE for further details | |
8 | """ | |
9 | # Copyright 2011 Marco Conti | |
10 | ||
11 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
12 | # you may not use this file except in compliance with the License. | |
13 | # You may obtain a copy of the License at | |
14 | ||
15 | # http://www.apache.org/licenses/LICENSE-2.0 | |
16 | ||
17 | # Unless required by applicable law or agreed to in writing, software | |
18 | # distributed under the License is distributed on an "AS IS" BASIS, | |
19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
20 | # See the License for the specific language governing permissions and | |
21 | # limitations under the License. | |
22 | ||
23 | # Thanks to grt for the fixes | |
24 | import datetime | |
25 | from odf.table import TableRow, TableCell, Table | |
26 | from odf.text import P | |
27 | from odf.namespaces import OFFICENS | |
28 | from odf.opendocument import OpenDocumentSpreadsheet, load | |
29 | from pyexcel_io import ( | |
30 | SheetReaderBase, | |
31 | BookReader, | |
32 | SheetWriter, | |
33 | BookWriter, | |
34 | READERS, | |
35 | WRITERS, | |
36 | isstream, | |
37 | get_data as read_data, | |
38 | store_data as write_data | |
39 | ) | |
40 | ||
41 | ||
42 | def float_value(value): | |
43 | ret = float(value) | |
44 | return ret | |
45 | ||
46 | ||
47 | def date_value(value): | |
48 | ret = "invalid" | |
49 | try: | |
50 | # catch strptime exceptions only | |
51 | if len(value) == 10: | |
52 | ret = datetime.datetime.strptime( | |
53 | value, | |
54 | "%Y-%m-%d") | |
55 | ret = ret.date() | |
56 | elif len(value) == 19: | |
57 | ret = datetime.datetime.strptime( | |
58 | value, | |
59 | "%Y-%m-%dT%H:%M:%S") | |
60 | elif len(value) > 19: | |
61 | ret = datetime.datetime.strptime( | |
62 | value[0:26], | |
63 | "%Y-%m-%dT%H:%M:%S.%f") | |
64 | except: | |
65 | pass | |
66 | if ret == "invalid": | |
67 | raise Exception("Bad date value %s" % value) | |
68 | return ret | |
69 | ||
70 | ||
71 | def ods_date_value(value): | |
72 | return value.strftime("%Y-%m-%d") | |
73 | ||
74 | ||
75 | def time_value(value): | |
76 | hour = int(value[2:4]) | |
77 | minute = int(value[5:7]) | |
78 | second = int(value[8:10]) | |
79 | if hour < 24: | |
80 | ret = datetime.time(hour, minute, second) | |
81 | else: | |
82 | ret = datetime.timedelta(hours=hour, minutes=minute, seconds=second) | |
83 | return ret | |
84 | ||
85 | ||
86 | def ods_time_value(value): | |
87 | return value.strftime("PT%HH%MM%SS") | |
88 | ||
89 | ||
90 | def boolean_value(value): | |
91 | if value == "true": | |
92 | ret = True | |
93 | else: | |
94 | ret = False | |
95 | return ret | |
96 | ||
97 | ||
98 | def ods_bool_value(value): | |
99 | if value is True: | |
100 | return "true" | |
101 | else: | |
102 | return "false" | |
103 | ||
104 | ||
105 | def ods_timedelta_value(cell): | |
106 | hours = cell.days * 24 + cell.seconds // 3600 | |
107 | minutes = (cell.seconds // 60) % 60 | |
108 | seconds = cell.seconds % 60 | |
109 | return "PT%02dH%02dM%02dS" % (hours, minutes, seconds) | |
110 | ||
111 | ||
112 | ODS_FORMAT_CONVERSION = { | |
113 | "float": float, | |
114 | "date": datetime.date, | |
115 | "time": datetime.time, | |
116 | 'timedelta': datetime.timedelta, | |
117 | "boolean": bool, | |
118 | "percentage": float, | |
119 | "currency": float | |
120 | } | |
121 | ||
122 | ||
123 | ODS_WRITE_FORMAT_COVERSION = { | |
124 | float: "float", | |
125 | int: "float", | |
126 | str: "string", | |
127 | datetime.date: "date", | |
128 | datetime.time: "time", | |
129 | datetime.timedelta: "timedelta", | |
130 | bool: "boolean", | |
131 | unicode: "string" | |
132 | } | |
133 | ||
134 | ||
135 | VALUE_CONVERTERS = { | |
136 | "float": float_value, | |
137 | "date": date_value, | |
138 | "time": time_value, | |
139 | "timedelta": time_value, | |
140 | "boolean": boolean_value, | |
141 | "percentage": float_value, | |
142 | "currency": float_value | |
143 | } | |
144 | ||
145 | ODS_VALUE_CONVERTERS = { | |
146 | "date": ods_date_value, | |
147 | "time": ods_time_value, | |
148 | "boolean": ods_bool_value, | |
149 | "timedelta": ods_timedelta_value | |
150 | } | |
151 | ||
152 | ||
153 | VALUE_TOKEN = { | |
154 | "float": "value", | |
155 | "date": "date-value", | |
156 | "time": "time-value", | |
157 | "boolean": "boolean-value", | |
158 | "percentage": "value", | |
159 | "currency": "value", | |
160 | "timedelta": "time-value" | |
161 | } | |
162 | ||
163 | ||
164 | class ODSSheet(SheetReaderBase): | |
165 | @property | |
166 | def name(self): | |
167 | return self.native_sheet.getAttribute("name") | |
168 | ||
169 | def to_array(self): | |
170 | """reads a sheet in the sheet dictionary, storing each sheet | |
171 | as an array (rows) of arrays (columns)""" | |
172 | rows = self.native_sheet.getElementsByType(TableRow) | |
173 | # for each row | |
174 | for row in rows: | |
175 | tmp_row = [] | |
176 | arr_cells = [] | |
177 | cells = row.getElementsByType(TableCell) | |
178 | ||
179 | # for each cell | |
180 | for cell in cells: | |
181 | # repeated value? | |
182 | repeat = cell.getAttribute("numbercolumnsrepeated") | |
183 | cell_value = self._read_cell(cell) | |
184 | if(not repeat): | |
185 | tmp_row.append(cell_value) | |
186 | else: | |
187 | r = int(repeat) | |
188 | for i in range(0, r): | |
189 | tmp_row.append(cell_value) | |
190 | if cell_value is not None and cell_value != '': | |
191 | arr_cells += tmp_row | |
192 | tmp_row = [] | |
193 | # if row contained something | |
194 | yield arr_cells | |
195 | ||
196 | def _read_text_cell(self, cell): | |
197 | textContent = [] | |
198 | ps = cell.getElementsByType(P) | |
199 | # for each text node | |
200 | for p in ps: | |
201 | for n in p.childNodes: | |
202 | if (n.nodeType == 3): | |
203 | textContent.append(unicode(n.data)) | |
204 | return '\n'.join(textContent) | |
205 | ||
206 | def _read_cell(self, cell): | |
207 | cell_type = cell.getAttrNS(OFFICENS, "value-type") | |
208 | value_token = VALUE_TOKEN.get(cell_type, "value") | |
209 | ret = None | |
210 | if cell_type == "string": | |
211 | textContent = self._read_text_cell(cell) | |
212 | ret = textContent | |
213 | else: | |
214 | if cell_type in ODS_FORMAT_CONVERSION: | |
215 | value = cell.getAttrNS(OFFICENS, value_token) | |
216 | n_value = VALUE_CONVERTERS[cell_type](value) | |
217 | ret = n_value | |
218 | else: | |
219 | textContent = self._read_text_cell(cell) | |
220 | ret = textContent | |
221 | return ret | |
222 | ||
223 | ||
224 | class ODSBook(BookReader): | |
225 | ||
226 | def get_sheet(self, native_sheet): | |
227 | return ODSSheet(native_sheet) | |
228 | ||
229 | def load_from_memory(self, file_content, **keywords): | |
230 | return load(file_content) | |
231 | ||
232 | def load_from_file(self, filename, **keywords): | |
233 | return load(filename) | |
234 | ||
235 | def sheet_iterator(self): | |
236 | if self.sheet_name is not None: | |
237 | tables = self.native_book.spreadsheet.getElementsByType(Table) | |
238 | rets = [table for table in tables | |
239 | if table.getAttribute('name') == self.sheet_name] | |
240 | if len(rets) == 0: | |
241 | raise ValueError("%s cannot be found" % self.sheet_name) | |
242 | else: | |
243 | return rets | |
244 | elif self.sheet_index is not None: | |
245 | tables = self.native_book.spreadsheet.getElementsByType(Table) | |
246 | length = len(tables) | |
247 | if self.sheet_index < length: | |
248 | return [tables[self.sheet_index]] | |
249 | else: | |
250 | raise IndexError("Index %d of out bound %d" % ( | |
251 | self.sheet_index, length)) | |
252 | else: | |
253 | return self.native_book.spreadsheet.getElementsByType(Table) | |
254 | ||
255 | ||
256 | class ODSSheetWriter(SheetWriter): | |
257 | """ | |
258 | ODS sheet writer | |
259 | """ | |
260 | def set_sheet_name(self, name): | |
261 | self.native_sheet = Table(name=name) | |
262 | ||
263 | def set_size(self, size): | |
264 | pass | |
265 | ||
266 | def write_cell(self, row, cell): | |
267 | tc = TableCell() | |
268 | cell_type = type(cell) | |
269 | cell_odf_type = ODS_WRITE_FORMAT_COVERSION.get(cell_type, "string") | |
270 | tc.setAttrNS(OFFICENS, "value-type", cell_odf_type) | |
271 | cell_odf_value_token = VALUE_TOKEN.get(cell_odf_type, "value") | |
272 | converter = ODS_VALUE_CONVERTERS.get(cell_odf_type, None) | |
273 | if converter: | |
274 | cell = converter(cell) | |
275 | if cell_odf_type != 'string': | |
276 | tc.setAttrNS(OFFICENS, cell_odf_value_token, cell) | |
277 | tc.addElement(P(text=cell)) | |
278 | else: | |
279 | lines = cell.split('\n') | |
280 | for line in lines: | |
281 | tc.addElement(P(text=line)) | |
282 | row.addElement(tc) | |
283 | ||
284 | def write_row(self, array): | |
285 | """ | |
286 | write a row into the file | |
287 | """ | |
288 | tr = TableRow() | |
289 | self.native_sheet.addElement(tr) | |
290 | for cell in array: | |
291 | self.write_cell(tr, cell) | |
292 | ||
293 | def close(self): | |
294 | """ | |
295 | This call writes file | |
296 | ||
297 | """ | |
298 | self.native_book.spreadsheet.addElement(self.native_sheet) | |
299 | ||
300 | ||
301 | class ODSWriter(BookWriter): | |
302 | """ | |
303 | open document spreadsheet writer | |
304 | ||
305 | """ | |
306 | def __init__(self, file, **keywords): | |
307 | BookWriter.__init__(self, file, **keywords) | |
308 | self.native_book = OpenDocumentSpreadsheet() | |
309 | ||
310 | def create_sheet(self, name): | |
311 | """ | |
312 | write a row into the file | |
313 | """ | |
314 | return ODSSheetWriter(self.native_book, None, name) | |
315 | ||
316 | def close(self): | |
317 | """ | |
318 | This call writes file | |
319 | ||
320 | """ | |
321 | self.native_book.write(self.file) | |
322 | ||
323 | # Register ods reader and writer | |
324 | READERS["ods"] = ODSBook | |
325 | WRITERS["ods"] = ODSWriter | |
326 | ||
327 | ||
328 | def save_data(afile, data, file_type=None, **keywords): | |
329 | """ | |
330 | Save all data to a file | |
331 | """ | |
332 | if isstream(afile) and file_type is None: | |
333 | file_type = 'ods' | |
334 | write_data(afile, data, file_type=file_type, **keywords) | |
335 | ||
336 | ||
337 | def get_data(afile, file_type=None, **keywords): | |
338 | """ | |
339 | Retrieve all data from incoming file | |
340 | """ | |
341 | if isstream(afile) and file_type is None: | |
342 | file_type = 'ods' | |
343 | return read_data(afile, file_type=file_type, **keywords) | |
344 |
0 | try: | |
1 | from setuptools import setup, find_packages | |
2 | except ImportError: | |
3 | from ez_setup import use_setuptools | |
4 | use_setuptools() | |
5 | from setuptools import setup, find_packages | |
6 | ||
7 | with open("README.rst", 'r') as readme: | |
8 | README_txt = readme.read() | |
9 | ||
10 | dependencies = [ | |
11 | 'pyexcel-io>=0.1.0', | |
12 | 'odfpy==0.9.6', | |
13 | ] | |
14 | ||
15 | extras = {} | |
16 | ||
17 | ||
18 | setup( | |
19 | name='pyexcel-ods', | |
20 | author='C. W.', | |
21 | version='0.1.0', | |
22 | author_email='wangc_2011 (at) hotmail.com', | |
23 | url='https://github.com/pyexcel/pyexcel-ods', | |
24 | description='A wrapper library to read, manipulate and write data in ods format', | |
25 | install_requires=dependencies, | |
26 | extras_require=extras, | |
27 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), | |
28 | include_package_data=True, | |
29 | long_description=README_txt, | |
30 | zip_safe=False, | |
31 | tests_require=['nose'], | |
32 | keywords=[ | |
33 | 'excel', | |
34 | 'python', | |
35 | 'pyexcel', | |
36 | ], | |
37 | license='New BSD', | |
38 | classifiers=[ | |
39 | 'Topic :: Office/Business', | |
40 | 'Topic :: Utilities', | |
41 | 'Topic :: Software Development :: Libraries', | |
42 | 'Programming Language :: Python', | |
43 | 'License :: OSI Approved :: BSD License', | |
44 | 'Intended Audience :: Developers', | |
45 | 'Programming Language :: Python :: 2.6', | |
46 | 'Programming Language :: Python :: 2.7' | |
47 | ] | |
48 | )⏎ |
0 | nosetests --with-cov --with-doctest --doctest-extension=.rst -I applymoban.py -I setup.py |
0 | nosetests --rednose --with-cov --cov pyexcel_ods --cov tests --with-doctest --doctest-extension=.rst |
0 | import os | |
1 | import pyexcel | |
2 | from nose.tools import raises | |
3 | import datetime | |
4 | ||
5 | ||
6 | def create_sample_file1(file): | |
7 | data=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 1.1, 1] | |
8 | table = [] | |
9 | table.append(data[:4]) | |
10 | table.append(data[4:8]) | |
11 | table.append(data[8:12]) | |
12 | pyexcel.save_as(array=table, dest_file_name=file) | |
13 | ||
14 | ||
15 | class PyexcelHatWriterBase: | |
16 | """ | |
17 | Abstract functional test for hat writers | |
18 | """ | |
19 | content = { | |
20 | "X": [1,2,3,4,5], | |
21 | "Y": [6,7,8,9,10], | |
22 | "Z": [11,12,13,14,15], | |
23 | } | |
24 | ||
25 | def test_series_table(self): | |
26 | pyexcel.save_as(adict=self.content, dest_file_name=self.testfile) | |
27 | r = pyexcel.get_sheet(file_name=self.testfile, name_columns_by_row=0) | |
28 | actual = pyexcel.utils.to_dict(r) | |
29 | assert actual == self.content | |
30 | ||
31 | ||
32 | class PyexcelWriterBase: | |
33 | """ | |
34 | Abstract functional test for writers | |
35 | ||
36 | testfile and testfile2 have to be initialized before | |
37 | it is used for testing | |
38 | """ | |
39 | content = [ | |
40 | [1,2,3,4,5], | |
41 | [1,2,3,4,5], | |
42 | [1,2,3,4,5], | |
43 | [1,2,3,4,5] | |
44 | ] | |
45 | ||
46 | def _create_a_file(self, file): | |
47 | pyexcel.save_as(dest_file_name=file,array=self.content) | |
48 | ||
49 | def test_write_array(self): | |
50 | self._create_a_file(self.testfile) | |
51 | r = pyexcel.get_sheet(file_name=self.testfile) | |
52 | actual = pyexcel.utils.to_array(r.rows()) | |
53 | assert actual == self.content | |
54 | ||
55 | ||
56 | class PyexcelMultipleSheetBase: | |
57 | ||
58 | def _write_test_file(self, filename): | |
59 | pyexcel.save_book_as(bookdict=self.content, dest_file_name=filename) | |
60 | ||
61 | def _clean_up(self): | |
62 | if os.path.exists(self.testfile2): | |
63 | os.unlink(self.testfile2) | |
64 | if os.path.exists(self.testfile): | |
65 | os.unlink(self.testfile) | |
66 | ||
67 | def test_sheet_names(self): | |
68 | r = pyexcel.BookReader( self.testfile) | |
69 | expected = [ "Sheet1", "Sheet2", "Sheet3"] | |
70 | sheet_names = r.sheet_names() | |
71 | for name in sheet_names: | |
72 | assert name in expected | |
73 | ||
74 | def test_reading_through_sheets(self): | |
75 | b = pyexcel.BookReader(self.testfile) | |
76 | data = pyexcel.utils.to_array(b["Sheet1"].rows()) | |
77 | expected = [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]] | |
78 | assert data == expected | |
79 | data = pyexcel.utils.to_array(b["Sheet2"].rows()) | |
80 | expected = [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6]] | |
81 | assert data == expected | |
82 | data = pyexcel.utils.to_array(b["Sheet3"].rows()) | |
83 | expected = [[u'X', u'Y', u'Z'], [1, 4, 7], [2, 5, 8], [3, 6, 9]] | |
84 | assert data == expected | |
85 | sheet3 = b["Sheet3"] | |
86 | sheet3.name_columns_by_row(0) | |
87 | data = pyexcel.utils.to_array(b["Sheet3"].rows()) | |
88 | expected = [[1, 4, 7], [2, 5, 8], [3, 6, 9]] | |
89 | assert data == expected | |
90 | ||
91 | def test_iterate_through_sheets(self): | |
92 | b = pyexcel.BookReader(self.testfile) | |
93 | for s in b: | |
94 | data = pyexcel.utils.to_array(s) | |
95 | assert self.content[s.name] == data | |
96 | si = pyexcel.iterators.SheetIterator(b) | |
97 | for s in si: | |
98 | data = pyexcel.utils.to_array(s) | |
99 | assert self.content[s.name] == data | |
100 | ||
101 | def test_random_access_operator(self): | |
102 | r = pyexcel.BookReader(self.testfile) | |
103 | value = r["Sheet1"][0,1] | |
104 | assert value == 1 | |
105 | value = r["Sheet3"][0,1] | |
106 | assert value == 'Y' | |
107 | r["Sheet3"].name_columns_by_row(0) | |
108 | assert r["Sheet3"][0,1] == 4 | |
109 | ||
110 | ||
111 | class ODSCellTypes: | |
112 | ||
113 | def test_formats(self): | |
114 | # date formats | |
115 | date_format = "%d/%m/%Y" | |
116 | assert self.data["Sheet1"][0][0] == "Date" | |
117 | assert self.data["Sheet1"][1][0].strftime(date_format) == "11/11/2014" | |
118 | assert self.data["Sheet1"][2][0].strftime(date_format) == "01/01/2001" | |
119 | assert self.data["Sheet1"][3][0] == "" | |
120 | # time formats | |
121 | time_format = "%S:%M:%H" | |
122 | assert self.data["Sheet1"][0][1] == "Time" | |
123 | assert self.data["Sheet1"][1][1].strftime(time_format) == "12:12:11" | |
124 | assert self.data["Sheet1"][2][1].strftime(time_format) == "12:00:00" | |
125 | assert self.data["Sheet1"][3][1] == 0 | |
126 | assert self.data["Sheet1"][4][1] == datetime.timedelta(hours=27, minutes=17, seconds=54) | |
127 | assert self.data["Sheet1"][5][1] == "Other" | |
128 | # boolean | |
129 | assert self.data["Sheet1"][0][2] == "Boolean" | |
130 | assert self.data["Sheet1"][1][2] is True | |
131 | assert self.data["Sheet1"][2][2] is False | |
132 | # Float | |
133 | assert self.data["Sheet1"][0][3] == "Float" | |
134 | assert self.data["Sheet1"][1][3] == 11.11 | |
135 | # Currency | |
136 | assert self.data["Sheet1"][0][4] == "Currency" | |
137 | assert self.data["Sheet1"][1][4] == 1 | |
138 | assert self.data["Sheet1"][2][4] == -10000 | |
139 | # Percentage | |
140 | assert self.data["Sheet1"][0][5] == "Percentage" | |
141 | assert self.data["Sheet1"][1][5] == 2 | |
142 | # int | |
143 | assert self.data["Sheet1"][0][6] == "Int" | |
144 | assert self.data["Sheet1"][1][6] == 3 | |
145 | assert self.data["Sheet1"][4][6] == 11 | |
146 | # Scientifed not supported | |
147 | assert self.data["Sheet1"][1][7] == 100000 | |
148 | # Fraction | |
149 | assert self.data["Sheet1"][1][8] == 1.25 | |
150 | # Text | |
151 | assert self.data["Sheet1"][1][9] == "abc" | |
152 | ||
153 | @raises(IndexError) | |
154 | def test_no_excessive_trailing_columns(self): | |
155 | assert self.data["Sheet1"][2][6] == "" |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 | #!/usr/bin/python | |
1 | # -*- encoding: utf-8 -*- | |
2 | import os | |
3 | from pyexcel_ods import get_data, save_data | |
4 | from nose.tools import raises | |
5 | ||
6 | ||
7 | def test_bug_fix_for_issue_1(): | |
8 | data = get_data(os.path.join("tests", "fixtures", "repeated.ods")) | |
9 | assert data == [['repeated', 'repeated', 'repeated', 'repeated']] | |
10 | ||
11 | def test_bug_fix_for_issue_2(): | |
12 | data = {} | |
13 | data.update({"Sheet 1": [[1, 2, 3], [4, 5, 6]]}) | |
14 | data.update({"Sheet 2": [[u"row 1", u"Héllô!", u"HolÁ!"]]}) | |
15 | save_data("your_file.ods", data) | |
16 | new_data = get_data("your_file.ods") | |
17 | assert new_data["Sheet 2"] == [[u'row 1', u'H\xe9ll\xf4!', u'Hol\xc1!']] | |
18 | ||
19 | def test_date_util_parse(): | |
20 | from pyexcel_ods import date_value | |
21 | value = "2015-08-17T19:20:00" | |
22 | d = date_value(value) | |
23 | assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:00" | |
24 | value = "2015-08-17" | |
25 | d = date_value(value) | |
26 | assert d.strftime("%Y-%m-%d") == "2015-08-17" | |
27 | value = "2015-08-17T19:20:59.999999" | |
28 | d = date_value(value) | |
29 | assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59" | |
30 | value = "2015-08-17T19:20:59.99999" | |
31 | d = date_value(value) | |
32 | assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59" | |
33 | value = "2015-08-17T19:20:59.999999999999999" | |
34 | d = date_value(value) | |
35 | assert d.strftime("%Y-%m-%dT%H:%M:%S") == "2015-08-17T19:20:59" | |
36 | ||
37 | @raises(Exception) | |
38 | def test_invalid_date(): | |
39 | from pyexcel_ods import date_value | |
40 | value = "2015-08-" | |
41 | date_value(value) | |
42 | ||
43 | @raises(Exception) | |
44 | def test_fake_date_time_10(): | |
45 | from pyexcel_ods import date_value | |
46 | date_value("1234567890") | |
47 | ||
48 | @raises(Exception) | |
49 | def test_fake_date_time_19(): | |
50 | from pyexcel_ods import date_value | |
51 | date_value("1234567890123456789") | |
52 | ||
53 | @raises(Exception) | |
54 | def test_fake_date_time_20(): | |
55 | from pyexcel_ods import date_value | |
56 | date_value("12345678901234567890") | |
57 | ⏎ |
0 | import os | |
1 | import pyexcel,pyexcel.ext.ods | |
2 | ||
3 | ||
4 | def test_reading_multiline_ods(): | |
5 | testfile = os.path.join("tests", "fixtures", "multilineods.ods") | |
6 | sheet = pyexcel.get_sheet(file_name=testfile) | |
7 | assert sheet[0,0] == '1\n2\n3\n4' | |
8 | ||
9 | ||
10 | def test_writing_multiline_ods(): | |
11 | content = "2\n3\n4\n993939\na" | |
12 | testfile = "writemultiline.ods" | |
13 | array = [[content,"test"]] | |
14 | pyexcel.save_as(array=array, dest_file_name=testfile) | |
15 | sheet = pyexcel.get_sheet(file_name=testfile) | |
16 | assert sheet[0,0] == content | |
17 | os.unlink(testfile) |
0 | from base import PyexcelMultipleSheetBase | |
1 | import pyexcel | |
2 | import os | |
3 | from pyexcel.ext import ods | |
4 | from pyexcel.ext import xls | |
5 | from nose.tools import raises | |
6 | import sys | |
7 | ||
8 | if sys.version_info[0] == 2 and sys.version_info[1] < 7: | |
9 | from ordereddict import OrderedDict | |
10 | else: | |
11 | from collections import OrderedDict | |
12 | ||
13 | ||
14 | class TestOdsNxlsMultipleSheets(PyexcelMultipleSheetBase): | |
15 | def setUp(self): | |
16 | self.testfile = "multiple1.ods" | |
17 | self.testfile2 = "multiple1.xls" | |
18 | self.content = { | |
19 | "Sheet1": [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], | |
20 | "Sheet2": [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6]], | |
21 | "Sheet3": [[u'X', u'Y', u'Z'], [1, 4, 7], [2, 5, 8], [3, 6, 9]] | |
22 | } | |
23 | self._write_test_file(self.testfile) | |
24 | ||
25 | def tearDown(self): | |
26 | self._clean_up() | |
27 | ||
28 | ||
29 | class TestXlsNOdsMultipleSheets(PyexcelMultipleSheetBase): | |
30 | def setUp(self): | |
31 | self.testfile = "multiple1.xls" | |
32 | self.testfile2 = "multiple1.ods" | |
33 | self.content = { | |
34 | "Sheet1": [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], | |
35 | "Sheet2": [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6]], | |
36 | "Sheet3": [[u'X', u'Y', u'Z'], [1, 4, 7], [2, 5, 8], [3, 6, 9]] | |
37 | } | |
38 | self._write_test_file(self.testfile) | |
39 | ||
40 | def tearDown(self): | |
41 | self._clean_up() | |
42 | ||
43 | ||
44 | class TestAddBooks: | |
45 | def _write_test_file(self, file): | |
46 | """ | |
47 | Make a test file as: | |
48 | ||
49 | 1,1,1,1 | |
50 | 2,2,2,2 | |
51 | 3,3,3,3 | |
52 | """ | |
53 | self.rows = 3 | |
54 | pyexcel.save_book_as(bookdict=self.content, dest_file_name=file) | |
55 | ||
56 | def setUp(self): | |
57 | self.testfile = "multiple1.ods" | |
58 | self.testfile2 = "multiple1.xls" | |
59 | self.content = OrderedDict() | |
60 | self.content.update({"Sheet1": [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]]}) | |
61 | self.content.update({"Sheet2": [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6]]}) | |
62 | self.content.update({"Sheet3": [[u'X', u'Y', u'Z'], [1, 4, 7], [2, 5, 8], [3, 6, 9]]}) | |
63 | self._write_test_file(self.testfile) | |
64 | self._write_test_file(self.testfile2) | |
65 | ||
66 | def test_load_a_single_sheet(self): | |
67 | b1 = pyexcel.load_book(self.testfile, sheet_name="Sheet1") | |
68 | assert len(b1.sheet_names()) == 1 | |
69 | assert b1['Sheet1'].to_array() == self.content['Sheet1'] | |
70 | ||
71 | def test_load_a_single_sheet2(self): | |
72 | b1 = pyexcel.load_book(self.testfile, sheet_index=0) | |
73 | assert len(b1.sheet_names()) == 1 | |
74 | assert b1['Sheet1'].to_array() == self.content['Sheet1'] | |
75 | ||
76 | @raises(IndexError) | |
77 | def test_load_a_single_sheet3(self): | |
78 | pyexcel.load_book(self.testfile, sheet_index=10000) | |
79 | ||
80 | @raises(ValueError) | |
81 | def test_load_a_single_sheet4(self): | |
82 | pyexcel.load_book(self.testfile, sheet_name="Not exist") | |
83 | ||
84 | def test_delete_sheets(self): | |
85 | b1 = pyexcel.load_book(self.testfile) | |
86 | assert len(b1.sheet_names()) == 3 | |
87 | del b1["Sheet1"] | |
88 | assert len(b1.sheet_names()) == 2 | |
89 | try: | |
90 | del b1["Sheet1"] | |
91 | assert 1==2 | |
92 | except KeyError: | |
93 | assert 1==1 | |
94 | del b1[1] | |
95 | assert len(b1.sheet_names()) == 1 | |
96 | try: | |
97 | del b1[1] | |
98 | assert 1==2 | |
99 | except IndexError: | |
100 | assert 1==1 | |
101 | ||
102 | def test_delete_sheets2(self): | |
103 | """repetitively delete first sheet""" | |
104 | b1 = pyexcel.load_book(self.testfile) | |
105 | del b1[0] | |
106 | assert len(b1.sheet_names()) == 2 | |
107 | del b1[0] | |
108 | assert len(b1.sheet_names()) == 1 | |
109 | del b1[0] | |
110 | assert len(b1.sheet_names()) == 0 | |
111 | ||
112 | def test_add_book1(self): | |
113 | """ | |
114 | test this scenario: book3 = book1 + book2 | |
115 | """ | |
116 | b1 = pyexcel.get_book(file_name=self.testfile) | |
117 | b2 = pyexcel.get_book(file_name=self.testfile2) | |
118 | b3 = b1 + b2 | |
119 | content = pyexcel.utils.to_dict(b3) | |
120 | sheet_names = content.keys() | |
121 | assert len(sheet_names) == 6 | |
122 | for name in sheet_names: | |
123 | if "Sheet3" in name: | |
124 | assert content[name] == self.content["Sheet3"] | |
125 | elif "Sheet2" in name: | |
126 | assert content[name] == self.content["Sheet2"] | |
127 | elif "Sheet1" in name: | |
128 | assert content[name] == self.content["Sheet1"] | |
129 | ||
130 | def test_add_book1_in_place(self): | |
131 | """ | |
132 | test this scenario book1 += book2 | |
133 | """ | |
134 | b1 = pyexcel.BookReader(self.testfile) | |
135 | b2 = pyexcel.BookReader(self.testfile2) | |
136 | b1 += b2 | |
137 | content = pyexcel.utils.to_dict(b1) | |
138 | sheet_names = content.keys() | |
139 | assert len(sheet_names) == 6 | |
140 | for name in sheet_names: | |
141 | if "Sheet3" in name: | |
142 | assert content[name] == self.content["Sheet3"] | |
143 | elif "Sheet2" in name: | |
144 | assert content[name] == self.content["Sheet2"] | |
145 | elif "Sheet1" in name: | |
146 | assert content[name] == self.content["Sheet1"] | |
147 | ||
148 | def test_add_book2(self): | |
149 | """ | |
150 | test this scenario book3 = book1 + sheet3 | |
151 | """ | |
152 | b1 = pyexcel.BookReader(self.testfile) | |
153 | b2 = pyexcel.BookReader(self.testfile2) | |
154 | b3 = b1 + b2["Sheet3"] | |
155 | content = pyexcel.utils.to_dict(b3) | |
156 | sheet_names = content.keys() | |
157 | assert len(sheet_names) == 4 | |
158 | for name in sheet_names: | |
159 | if "Sheet3" in name: | |
160 | assert content[name] == self.content["Sheet3"] | |
161 | elif "Sheet2" in name: | |
162 | assert content[name] == self.content["Sheet2"] | |
163 | elif "Sheet1" in name: | |
164 | assert content[name] == self.content["Sheet1"] | |
165 | ||
166 | def test_add_book2_in_place(self): | |
167 | """ | |
168 | test this scenario book3 = book1 + sheet3 | |
169 | """ | |
170 | b1 = pyexcel.BookReader(self.testfile) | |
171 | b2 = pyexcel.BookReader(self.testfile2) | |
172 | b1 += b2["Sheet3"] | |
173 | content = pyexcel.utils.to_dict(b1) | |
174 | sheet_names = content.keys() | |
175 | assert len(sheet_names) == 4 | |
176 | for name in sheet_names: | |
177 | if "Sheet3" in name: | |
178 | assert content[name] == self.content["Sheet3"] | |
179 | elif "Sheet2" in name: | |
180 | assert content[name] == self.content["Sheet2"] | |
181 | elif "Sheet1" in name: | |
182 | assert content[name] == self.content["Sheet1"] | |
183 | ||
184 | def test_add_book3(self): | |
185 | """ | |
186 | test this scenario book3 = sheet1 + sheet2 | |
187 | """ | |
188 | b1 = pyexcel.BookReader(self.testfile) | |
189 | b2 = pyexcel.BookReader(self.testfile2) | |
190 | b3 = b1["Sheet1"] + b2["Sheet3"] | |
191 | content = pyexcel.utils.to_dict(b3) | |
192 | sheet_names = content.keys() | |
193 | assert len(sheet_names) == 2 | |
194 | assert content["Sheet3"] == self.content["Sheet3"] | |
195 | assert content["Sheet1"] == self.content["Sheet1"] | |
196 | ||
197 | def test_add_book4(self): | |
198 | """ | |
199 | test this scenario book3 = sheet1 + book | |
200 | """ | |
201 | b1 = pyexcel.BookReader(self.testfile) | |
202 | b2 = pyexcel.BookReader(self.testfile2) | |
203 | b3 = b1["Sheet1"] + b2 | |
204 | content = pyexcel.utils.to_dict(b3) | |
205 | sheet_names = content.keys() | |
206 | assert len(sheet_names) == 4 | |
207 | for name in sheet_names: | |
208 | if "Sheet3" in name: | |
209 | assert content[name] == self.content["Sheet3"] | |
210 | elif "Sheet2" in name: | |
211 | assert content[name] == self.content["Sheet2"] | |
212 | elif "Sheet1" in name: | |
213 | assert content[name] == self.content["Sheet1"] | |
214 | ||
215 | def test_add_book_error(self): | |
216 | """ | |
217 | test this scenario: book3 = sheet1 + book | |
218 | """ | |
219 | b1 = pyexcel.BookReader(self.testfile) | |
220 | try: | |
221 | b1 + 12 | |
222 | assert 1==2 | |
223 | except TypeError: | |
224 | assert 1==1 | |
225 | try: | |
226 | b1 += 12 | |
227 | assert 1==2 | |
228 | except TypeError: | |
229 | assert 1==1 | |
230 | ||
231 | def tearDown(self): | |
232 | if os.path.exists(self.testfile): | |
233 | os.unlink(self.testfile) | |
234 | if os.path.exists(self.testfile2): | |
235 | os.unlink(self.testfile2) | |
236 | ||
237 | ||
238 | class TestMultiSheetReader: | |
239 | def setUp(self): | |
240 | self.testfile = "file_with_an_empty_sheet.ods" | |
241 | ||
242 | def test_reader_with_correct_sheets(self): | |
243 | r = pyexcel.BookReader(os.path.join("tests", "fixtures", self.testfile)) | |
244 | assert r.number_of_sheets() == 3 |
0 | import os | |
1 | from pyexcel.ext import ods | |
2 | from base import ODSCellTypes | |
3 | ||
4 | ||
5 | class TestODSReader(ODSCellTypes): | |
6 | def setUp(self): | |
7 | r = ods.ODSBook(os.path.join("tests", | |
8 | "fixtures", | |
9 | "ods_formats.ods")) | |
10 | self.data = r.sheets() | |
11 | for key in self.data.keys(): | |
12 | self.data[key] = list(self.data[key]) | |
13 | ||
14 | ||
15 | class TestODSWriter(ODSCellTypes): | |
16 | def setUp(self): | |
17 | r = ods.ODSBook(os.path.join("tests", | |
18 | "fixtures", | |
19 | "ods_formats.ods")) | |
20 | self.data1 = r.sheets() | |
21 | self.testfile = "odswriter.ods" | |
22 | w = ods.ODSWriter(self.testfile) | |
23 | w.write(self.data1) | |
24 | w.close() | |
25 | r2 = ods.ODSBook(self.testfile) | |
26 | self.data = r2.sheets() | |
27 | for key in self.data.keys(): | |
28 | self.data[key] = list(self.data[key]) | |
29 | ||
30 | def tearDown(self): | |
31 | if os.path.exists(self.testfile): | |
32 | os.unlink(self.testfile) |
0 | import os | |
1 | import pyexcel | |
2 | from pyexcel.ext import ods | |
3 | from StringIO import StringIO | |
4 | from base import create_sample_file1 | |
5 | ||
6 | ||
7 | class TestStringIO: | |
8 | ||
9 | def test_ods_stringio(self): | |
10 | odsfile = "cute.ods" | |
11 | create_sample_file1(odsfile) | |
12 | with open(odsfile, "rb") as f: | |
13 | content = f.read() | |
14 | r = pyexcel.Reader(("ods", content)) | |
15 | result=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 1.1, 1] | |
16 | actual = pyexcel.utils.to_array(r.enumerate()) | |
17 | assert result == actual | |
18 | if os.path.exists(odsfile): | |
19 | os.unlink(odsfile) | |
20 | ||
21 | ||
22 | def test_xls_output_stringio(self): | |
23 | data = [ | |
24 | [1, 2, 3], | |
25 | [4, 5, 6] | |
26 | ] | |
27 | io = pyexcel.save_as(dest_file_type='ods', array=data) | |
28 | r = pyexcel.Reader(("ods", io.getvalue())) | |
29 | result=[1, 2, 3, 4, 5, 6] | |
30 | actual = pyexcel.utils.to_array(r.enumerate()) | |
31 | assert result == actual⏎ |
0 | import os | |
1 | from pyexcel.ext import ods | |
2 | from base import PyexcelWriterBase, PyexcelHatWriterBase | |
3 | ||
4 | ||
5 | class TestNativeODSWriter: | |
6 | def test_write_book(self): | |
7 | self.content = { | |
8 | "Sheet1": [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], | |
9 | "Sheet2": [[4, 4, 4, 4], [5, 5, 5, 5], [6, 6, 6, 6]], | |
10 | "Sheet3": [[u'X', u'Y', u'Z'], [1, 4, 7], [2, 5, 8], [3, 6, 9]] | |
11 | } | |
12 | self.testfile = "odswriter.ods" | |
13 | writer = ods.ODSWriter(self.testfile) | |
14 | writer.write(self.content) | |
15 | writer.close() | |
16 | reader = ods.ODSBook(self.testfile) | |
17 | content = reader.sheets() | |
18 | for key in content.keys(): | |
19 | content[key] = list(content[key]) | |
20 | assert content == self.content | |
21 | ||
22 | def tearDown(self): | |
23 | if os.path.exists(self.testfile): | |
24 | os.unlink(self.testfile) | |
25 | ||
26 | ||
27 | class TestODSnCSVWriter(PyexcelWriterBase): | |
28 | def setUp(self): | |
29 | self.testfile="testods.ods" | |
30 | self.testfile2="test.csv" | |
31 | ||
32 | def tearDown(self): | |
33 | if os.path.exists(self.testfile): | |
34 | os.unlink(self.testfile) | |
35 | if os.path.exists(self.testfile2): | |
36 | os.unlink(self.testfile2) | |
37 | ||
38 | ||
39 | class TestODSHatWriter(PyexcelHatWriterBase): | |
40 | def setUp(self): | |
41 | self.testfile="testhat.ods" | |
42 | ||
43 | def tearDown(self): | |
44 | if os.path.exists(self.testfile): | |
45 | os.unlink(self.testfile) | |
46 | ||
47 |