├── .gitignore ├── .moban.d ├── README.rst ├── requirements.txt ├── setup.py ├── test.bat ├── test.sh ├── tests │ └── requirements.txt └── travis.jj2 ├── .moban.yml ├── .travis.yml ├── CHANGELOG.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── requirements.txt ├── resources ├── _static │ ├── handsontable.full.min.css │ └── handsontable.full.min.js └── _templates │ └── layout.html ├── rnd_requirements.txt ├── setup.py ├── sphinx-doc-source.png ├── sphinx-doc-view.png ├── sphinxcontrib-excel.yml ├── sphinxcontrib ├── __init__.py └── excel.py ├── test.bat ├── test.sh └── tests ├── fixtures └── test.csv ├── requirements.txt └── test_excel.py /.gitignore: -------------------------------------------------------------------------------- 1 | # April 2016 2 | # reference: https://github.com/github/gitignore/blob/master/Python.gitignore 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # IPython Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # dotenv 81 | .env 82 | 83 | # virtualenv 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | # emacs 94 | *~ 95 | 96 | # moban hashes 97 | .moban.hashes 98 | .DS_store 99 | 100 | -------------------------------------------------------------------------------- /.moban.d/README.rst: -------------------------------------------------------------------------------- 1 | {% extends "BASIC-README.rst.jj2" %} 2 | 3 | {%block documentation_link%} 4 | {%endblock%} 5 | 6 | {%block constraint%} 7 | {%endblock%} 8 | 9 | {%block features %} 10 | **{{name}}** uses pyexcel to read an excel files and renders into an excel-alike sheet in your sphinx documentation. The excel file formats are: 11 | 12 | #. csv 13 | #. tsv 14 | #. csvz 15 | #. tsvz 16 | #. xls 17 | #. xlsx 18 | #. xlsm 19 | #. ods 20 | 21 | {%endblock%} 22 | 23 | {%block usage%} 24 | 25 | Setup 26 | ================================================================================ 27 | 28 | Please add sphinxcontrib-excel into your conf.py file:: 29 | 30 | extensions = [ 31 | ... 32 | 'sphinxcontrib.excel', 33 | ... 34 | ] 35 | 36 | And you will need to copy a few resources file to your sphinx source directory:: 37 | 38 | resources/_template/layout.html 39 | resources/_static/handsontable.full.min.js 40 | resources/_static/handsontable.full.min.css 41 | 42 | .. note:: 43 | 44 | `resources` directory is in github. please check it out. 45 | 46 | Here is the syntax to present your excel file in sphinx documentation:: 47 | 48 | .. pyexcel-table:: filename.csv 49 | 50 | And 'filename.csv' is expected in the directory where the referring rst file is. 51 | Relative path needs to be given if your file is somewhere else. 52 | 53 | For example, the following rst statment: 54 | 55 | .. image:: https://github.com/pyexcel/sphinxcontrib-excel/raw/master/sphinx-doc-source.png 56 | :alt: table directive 57 | 58 | is translated as: 59 | 60 | .. image:: https://github.com/pyexcel/sphinxcontrib-excel/raw/master/sphinx-doc-view.png 61 | :alt: table view 62 | 63 | Embed csv into your sphinx documentation 64 | -------------------------------------------------- 65 | 66 | Here is the syntax for embedded csv, `rendering as a single handsontable `_: 67 | 68 | .. code-block:: 69 | 70 | .. pyexcel-table:: 71 | 72 | ---pyexcel:example table--- 73 | Name,Age 74 | Adam,28 75 | Beatrice,29 76 | Ceri,30 77 | Dean,26 78 | 79 | Here is the complex example for embedded csv, which will be `rendered as 80 | multi-tab handsontable `_): 81 | 82 | 83 | .. code-block:: 84 | 85 | .. pyexcel-table:: 86 | 87 | ---pyexcel:Sheet 1--- 88 | 1,2,3 89 | 4,5,6 90 | 7,8,9 91 | ---pyexcel--- 92 | ---pyexcel:Sheet 2--- 93 | X,Y,Z 94 | 1,2,3 95 | 4,5,6 96 | ---pyexcel--- 97 | ---pyexcel:Sheet 3--- 98 | O,P,Q 99 | 3,2,1 100 | 4,3,2 101 | 102 | 103 | {%endblock%} 104 | -------------------------------------------------------------------------------- /.moban.d/requirements.txt: -------------------------------------------------------------------------------- 1 | {% for dependency in dependencies: %} 2 | {{dependency}} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /.moban.d/setup.py: -------------------------------------------------------------------------------- 1 | {%extends "pyexcel-setup.py.jj2"%} 2 | 3 | {%block platform_block%} 4 | {%endblock%} 5 | -------------------------------------------------------------------------------- /.moban.d/test.bat: -------------------------------------------------------------------------------- 1 | {% extends "test.sh.jj2" %} 2 | 3 | {%block pretest %} 4 | cd tests\test_plugin 5 | python setup.py install 6 | cd ..\..\ 7 | {%endblock %} 8 | 9 | {%block flake8_options%} 10 | --builtins=unicode,xrange,long 11 | {%endblock%} 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.moban.d/test.sh: -------------------------------------------------------------------------------- 1 | {% extends "test.sh.jj2" %} 2 | 3 | {%block pretest %} 4 | #/bin/bash 5 | 6 | cd tests/test_plugin 7 | python setup.py install 8 | cd ../../ 9 | {%endblock %} 10 | 11 | {%block flake8_options%} 12 | --builtins=unicode,xrange,long 13 | {%endblock%} 14 | -------------------------------------------------------------------------------- /.moban.d/tests/requirements.txt: -------------------------------------------------------------------------------- 1 | {% extends 'tests/requirements.txt.jj2' %} 2 | {%block extras %} 3 | pyexcel 4 | {%endblock%} 5 | -------------------------------------------------------------------------------- /.moban.d/travis.jj2: -------------------------------------------------------------------------------- 1 | {% extends "travis.yml.jj2" %} 2 | 3 | {%block custom_python_versions%} 4 | python: 5 | - pypy 6 | - 3.6 7 | - 3.5 8 | - 3.4 9 | - 3.3 10 | - 2.7 11 | {%endblock%} 12 | -------------------------------------------------------------------------------- /.moban.yml: -------------------------------------------------------------------------------- 1 | configuration: 2 | configuration_dir: "commons/config" 3 | template_dir: 4 | - "commons/templates" 5 | - "setupmobans/templates" 6 | - ".moban.d" 7 | configuration: sphinxcontrib-excel.yml 8 | targets: 9 | - README.rst: README.rst 10 | - setup.py: setup.py 11 | - requirements.txt: requirements.txt 12 | - "tests/requirements.txt": "tests/requirements.txt" 13 | - test.sh: test.script.jj2 14 | - test.bat: test.script.jj2 15 | - .gitignore: gitignore.jj2 16 | - .travis.yml: travis.jj2 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | notifications: 4 | email: false 5 | python: 6 | - pypy 7 | - 3.6 8 | - 3.5 9 | - 3.4 10 | - 3.3 11 | - 2.7 12 | before_install: 13 | - if [[ $TRAVIS_PYTHON_VERSION == "2.6" ]]; then pip install flake8==2.6.2; fi 14 | - if [[ -f min_requirements.txt && "$MINREQ" -eq 1 ]]; then 15 | mv min_requirements.txt requirements.txt ; 16 | fi 17 | - test ! -f rnd_requirements.txt || pip install --no-deps -r rnd_requirements.txt 18 | - test ! -f rnd_requirements.txt || pip install -r rnd_requirements.txt ; 19 | - pip install -r tests/requirements.txt 20 | script: 21 | - make test 22 | after_success: 23 | codecov 24 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Change log 2 | =========== 3 | 4 | 0.0.1 - 21.06.2017 5 | -------------------------------------------------------------------------------- 6 | 7 | Initial release. Support 'pyexcel-table' directive in your sphinx documentation 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2017 by Onni Software Ltd. and its contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms of the software as well 5 | as documentation, with or without modification, are permitted provided 6 | that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | * Neither the name of 'sphinxcontrib-excel' nor the names of the contributors 16 | may not be used to endorse or promote products derived from this software 17 | without specific prior written permission. 18 | 19 | THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND 20 | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 21 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 23 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 30 | DAMAGE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include CHANGELOG.rst 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | 3 | test: 4 | bash test.sh 5 | 6 | document: 7 | bash document.sh 8 | 9 | css: 10 | python -mscss .moban.d/handsontable/style.css.jj2 11 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | sphinxcontrib-excel - Let you focus on data, instead of file formats 3 | ================================================================================ 4 | 5 | .. image:: https://raw.githubusercontent.com/pyexcel/pyexcel.github.io/master/images/patreon.png 6 | :target: https://www.patreon.com/pyexcel 7 | 8 | .. image:: https://api.travis-ci.org/pyexcel/sphinxcontrib-excel.svg?branch=master 9 | :target: http://travis-ci.org/pyexcel/sphinxcontrib-excel 10 | 11 | .. image:: https://codecov.io/gh/pyexcel/sphinxcontrib-excel/branch/master/graph/badge.svg 12 | :target: https://codecov.io/gh/pyexcel/sphinxcontrib-excel 13 | 14 | .. image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg 15 | :target: https://gitter.im/pyexcel/Lobby 16 | 17 | 18 | Support the project 19 | ================================================================================ 20 | 21 | If your company has embedded pyexcel and its components into a revenue generating 22 | product, please `support me on patreon `_ to 23 | maintain the project and develop it further. 24 | 25 | If you are an individual, you are welcome to support me too on patreon and for however long 26 | you feel like to. As a patreon, you will receive 27 | `early access to pyexcel related contents `_. 28 | 29 | With your financial support, I will be able to invest 30 | a little bit more time in coding, documentation and writing interesting posts. 31 | 32 | 33 | 34 | Introduction 35 | ================================================================================ 36 | **sphinxcontrib-excel** uses pyexcel to read an excel files and renders into an excel-alike sheet in your sphinx documentation. The excel file formats are: 37 | 38 | #. csv 39 | #. tsv 40 | #. csvz 41 | #. tsvz 42 | #. xls 43 | #. xlsx 44 | #. xlsm 45 | #. ods 46 | 47 | 48 | 49 | 50 | Installation 51 | ================================================================================ 52 | You can install it via pip: 53 | 54 | .. code-block:: bash 55 | 56 | $ pip install sphinxcontrib-excel 57 | 58 | 59 | or clone it and install it: 60 | 61 | .. code-block:: bash 62 | 63 | $ git clone https://github.com/pyexcel/sphinxcontrib-excel.git 64 | $ cd sphinxcontrib-excel 65 | $ python setup.py install 66 | 67 | 68 | 69 | Setup 70 | ================================================================================ 71 | 72 | Please add sphinxcontrib-excel into your conf.py file:: 73 | 74 | extensions = [ 75 | ... 76 | 'sphinxcontrib.excel', 77 | ... 78 | ] 79 | 80 | And you will need to copy a few resources file to your sphinx source directory:: 81 | 82 | resources/_template/layout.html 83 | resources/_static/handsontable.full.min.js 84 | resources/_static/handsontable.full.min.css 85 | 86 | .. note:: 87 | 88 | `resources` directory is in github. please check it out. 89 | 90 | Here is the syntax to present your excel file in sphinx documentation:: 91 | 92 | .. pyexcel-table:: filename.csv 93 | 94 | And 'filename.csv' is expected in the directory where the referring rst file is. 95 | Relative path needs to be given if your file is somewhere else. 96 | 97 | For example, the following rst statment: 98 | 99 | .. image:: https://github.com/pyexcel/sphinxcontrib-excel/raw/master/sphinx-doc-source.png 100 | :alt: table directive 101 | 102 | is translated as: 103 | 104 | .. image:: https://github.com/pyexcel/sphinxcontrib-excel/raw/master/sphinx-doc-view.png 105 | :alt: table view 106 | 107 | Embed csv into your sphinx documentation 108 | -------------------------------------------------- 109 | 110 | Here is the syntax for embedded csv, `rendering as a single handsontable `_: 111 | 112 | .. code-block:: 113 | 114 | .. pyexcel-table:: 115 | 116 | ---pyexcel:example table--- 117 | Name,Age 118 | Adam,28 119 | Beatrice,29 120 | Ceri,30 121 | Dean,26 122 | 123 | Here is the complex example for embedded csv, which will be `rendered as 124 | multi-tab handsontable `_): 125 | 126 | 127 | .. code-block:: 128 | 129 | .. pyexcel-table:: 130 | 131 | ---pyexcel:Sheet 1--- 132 | 1,2,3 133 | 4,5,6 134 | 7,8,9 135 | ---pyexcel--- 136 | ---pyexcel:Sheet 2--- 137 | X,Y,Z 138 | 1,2,3 139 | 4,5,6 140 | ---pyexcel--- 141 | ---pyexcel:Sheet 3--- 142 | O,P,Q 143 | 3,2,1 144 | 4,3,2 145 | 146 | 147 | 148 | Development guide 149 | ================================================================================ 150 | 151 | Development steps for code changes 152 | 153 | #. git clone https://github.com/pyexcel/sphinxcontrib-excel.git 154 | #. cd sphinxcontrib-excel 155 | 156 | Upgrade your setup tools and pip. They are needed for development and testing only: 157 | 158 | #. pip install --upgrade setuptools pip 159 | 160 | Then install relevant development requirements: 161 | 162 | #. pip install -r rnd_requirements.txt # if such a file exists 163 | #. pip install -r requirements.txt 164 | #. pip install -r tests/requirements.txt 165 | 166 | Once you have finished your changes, please provide test case(s), relevant documentation 167 | and update CHANGELOG.rst. 168 | 169 | .. note:: 170 | 171 | As to rnd_requirements.txt, usually, it is created when a dependent 172 | library is not released. Once the dependecy is installed 173 | (will be released), the future 174 | version of the dependency in the requirements.txt will be valid. 175 | 176 | 177 | How to test your contribution 178 | ------------------------------ 179 | 180 | Although `nose` and `doctest` are both used in code testing, it is adviable that unit tests are put in tests. `doctest` is incorporated only to make sure the code examples in documentation remain valid across different development releases. 181 | 182 | On Linux/Unix systems, please launch your tests like this:: 183 | 184 | $ make 185 | 186 | On Windows systems, please issue this command:: 187 | 188 | > test.bat 189 | 190 | How to update test environment and update documentation 191 | --------------------------------------------------------- 192 | 193 | Additional steps are required: 194 | 195 | #. pip install moban 196 | #. git clone https://github.com/moremoban/setupmobans.git # generic setup 197 | #. git clone https://github.com/pyexcel/pyexcel-commons.git commons 198 | #. make your changes in `.moban.d` directory, then issue command `moban` 199 | 200 | What is pyexcel-commons 201 | --------------------------------- 202 | 203 | Many information that are shared across pyexcel projects, such as: this developer guide, license info, etc. are stored in `pyexcel-commons` project. 204 | 205 | What is .moban.d 206 | --------------------------------- 207 | 208 | `.moban.d` stores the specific meta data for the library. 209 | 210 | Acceptance criteria 211 | ------------------- 212 | 213 | #. Has Test cases written 214 | #. Has all code lines tested 215 | #. Passes all Travis CI builds 216 | #. Has fair amount of documentation if your change is complex 217 | #. Please update CHANGELOG.rst 218 | #. Please add yourself to CONTRIBUTORS.rst 219 | #. Agree on NEW BSD License for your contribution 220 | 221 | 222 | 223 | License 224 | ================================================================================ 225 | 226 | New BSD License 227 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | docutils 2 | pyexcel>=0.5.0 3 | pyexcel-xls>=0.4.0 4 | pyexcel-odsr>=0.4.0 5 | pyexcel-handsontable 6 | sphinx 7 | -------------------------------------------------------------------------------- /resources/_static/handsontable.full.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";/*! 2 | (The MIT License) 3 | 4 | Copyright (c) 2012-2014 Marcin Warpechowski 5 | Copyright (c) 2015 Handsoncode sp. z o.o. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | 'Software'), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | */.handsontable{position:relative}.handsontable .hide{display:none}.handsontable .relative{position:relative}.handsontable.htAutoSize{visibility:hidden;left:-99000px;position:absolute;top:-99000px}.handsontable .wtHider{width:0}.handsontable .wtSpreader{position:relative;width:0;height:auto}.handsontable table,.handsontable tbody,.handsontable thead,.handsontable td,.handsontable th,.handsontable input,.handsontable textarea,.handsontable div{box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box}.handsontable input,.handsontable textarea{min-height:initial}.handsontable table.htCore{border-collapse:separate;border-spacing:0;margin:0;border-width:0;table-layout:fixed;width:0;outline-width:0;max-width:none;max-height:none}.handsontable col{width:50px}.handsontable col.rowHeader{width:50px}.handsontable th,.handsontable td{border-top-width:0;border-left-width:0;border-right:1px solid #CCC;border-bottom:1px solid #CCC;height:22px;empty-cells:show;line-height:21px;padding:0 4px 0 4px;background-color:#FFF;vertical-align:top;overflow:hidden;outline-width:0;white-space:pre-line;background-clip:padding-box}.handsontable td.htInvalid{background-color:#ff4c42!important}.handsontable td.htNoWrap{white-space:nowrap}.handsontable th:last-child{border-right:1px solid #CCC;border-bottom:1px solid #CCC}.handsontable tr:first-child th.htNoFrame,.handsontable th:first-child.htNoFrame,.handsontable th.htNoFrame{border-left-width:0;background-color:white;border-color:#FFF}.handsontable th:first-child,.handsontable th:nth-child(2),.handsontable td:first-of-type,.handsontable .htNoFrame+th,.handsontable .htNoFrame+td{border-left:1px solid #CCC}.handsontable.htRowHeaders thead tr th:nth-child(2){border-left:1px solid #CCC}.handsontable tr:first-child th,.handsontable tr:first-child td{border-top:1px solid #CCC}.ht_master:not(.innerBorderLeft):not(.emptyColumns) ~ .handsontable tbody tr th,.ht_master:not(.innerBorderLeft):not(.emptyColumns) ~ .handsontable:not(.ht_clone_top) thead tr th:first-child{border-right-width:0}.ht_master:not(.innerBorderTop) thead tr:last-child th,.ht_master:not(.innerBorderTop) ~ .handsontable thead tr:last-child th,.ht_master:not(.innerBorderTop) thead tr.lastChild th,.ht_master:not(.innerBorderTop) ~ .handsontable thead tr.lastChild th{border-bottom-width:0}.handsontable th{background-color:#f3f3f3;color:#222;text-align:center;font-weight:normal;white-space:nowrap}.handsontable thead th{padding:0}.handsontable th.active{background-color:#CCC}.handsontable thead th .relative{padding:2px 4px}.handsontable tbody th.ht__highlight,.handsontable thead th.ht__highlight{background-color:#dcdcdc}.handsontable.ht__selection--columns thead th.ht__highlight,.handsontable.ht__selection--rows tbody th.ht__highlight{background-color:#8eb0e7;color:#000}.handsontable .manualColumnResizer{position:fixed;top:0;cursor:col-resize;z-index:110;width:5px;height:25px}.handsontable .manualRowResizer{position:fixed;left:0;cursor:row-resize;z-index:110;height:5px;width:50px}.handsontable .manualColumnResizer:hover,.handsontable .manualColumnResizer.active,.handsontable .manualRowResizer:hover,.handsontable .manualRowResizer.active{background-color:#AAB}.handsontable .manualColumnResizerGuide{position:fixed;right:0;top:0;background-color:#AAB;display:none;width:0;border-right:1px dashed #777;margin-left:5px}.handsontable .manualRowResizerGuide{position:fixed;left:0;bottom:0;background-color:#AAB;display:none;height:0;border-bottom:1px dashed #777;margin-top:5px}.handsontable .manualColumnResizerGuide.active,.handsontable .manualRowResizerGuide.active{display:block;z-index:199}.handsontable .columnSorting{position:relative}.handsontable .columnSorting:hover{text-decoration:underline;cursor:pointer}.handsontable .columnSorting.ascending::after{content:'\25B2';color:#5f5f5f;position:absolute;right:-15px}.handsontable .columnSorting.descending::after{content:'\25BC';color:#5f5f5f;position:absolute;right:-15px}.handsontable .wtBorder{position:absolute;font-size:0}.handsontable .wtBorder.hidden{display:none!important}.handsontable td.area{background:-moz-linear-gradient(top,rgba(181,209,255,0.34) 0,rgba(181,209,255,0.34) 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,rgba(181,209,255,0.34)),color-stop(100%,rgba(181,209,255,0.34)));background:-webkit-linear-gradient(top,rgba(181,209,255,0.34) 0,rgba(181,209,255,0.34) 100%);background:-o-linear-gradient(top,rgba(181,209,255,0.34) 0,rgba(181,209,255,0.34) 100%);background:-ms-linear-gradient(top,rgba(181,209,255,0.34) 0,rgba(181,209,255,0.34) 100%);background:linear-gradient(to bottom,rgba(181,209,255,0.34) 0,rgba(181,209,255,0.34) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#57b5d1ff',endColorstr='#57b5d1ff',GradientType=0);background-color:#fff}.handsontable .wtBorder.corner{font-size:0;cursor:crosshair}.handsontable .htBorder.htFillBorder{background:red;width:1px;height:1px}.handsontableInput{border:0;outline-width:0;margin:0;padding:1px 5px 0 5px;font-family:inherit;line-height:21px;font-size:inherit;box-shadow:0 0 0 2px #5292f7 inset;resize:none;display:inline-block;color:#000;border-radius:0;background-color:#FFF}.handsontableInputHolder{position:absolute;top:0;left:0;z-index:100}.htSelectEditor{-webkit-appearance:menulist-button!important;position:absolute;width:auto}.handsontable .htDimmed{color:#777}.handsontable .htSubmenu{position:relative}.handsontable .htSubmenu :after{content:'▶';color:#777;position:absolute;right:5px}.handsontable .htLeft{text-align:left}.handsontable .htCenter{text-align:center}.handsontable .htRight{text-align:right}.handsontable .htJustify{text-align:justify}.handsontable .htTop{vertical-align:top}.handsontable .htMiddle{vertical-align:middle}.handsontable .htBottom{vertical-align:bottom}.handsontable .htPlaceholder{color:#999}.handsontable .htAutocompleteArrow{float:right;font-size:10px;color:#EEE;cursor:default;width:16px;text-align:center}.handsontable td .htAutocompleteArrow:hover{color:#777}.handsontable td.area .htAutocompleteArrow{color:#d3d3d3}.handsontable .htCheckboxRendererInput{display:inline-block;vertical-align:middle}.handsontable .htCheckboxRendererInput.noValue{opacity:.5}.handsontable .htCheckboxRendererLabel{cursor:pointer;display:inline-block;width:100%}@-webkit-keyframes opacity-hide{from{opacity:1}to{opacity:0}}@keyframes opacity-hide{from{opacity:1}to{opacity:0}}@-webkit-keyframes opacity-show{from{opacity:0}to{opacity:1}}@keyframes opacity-show{from{opacity:0}to{opacity:1}}.handsontable .handsontable.ht_clone_top .wtHider{padding:0 0 5px 0}.handsontable .autocompleteEditor.handsontable{padding-right:17px}.handsontable .autocompleteEditor.handsontable.htMacScroll{padding-right:15px}.handsontable.listbox{margin:0}.handsontable.listbox .ht_master table{border:1px solid #ccc;border-collapse:separate;background:white}.handsontable.listbox th,.handsontable.listbox tr:first-child th,.handsontable.listbox tr:last-child th,.handsontable.listbox tr:first-child td,.handsontable.listbox td{border-color:transparent}.handsontable.listbox th,.handsontable.listbox td{white-space:nowrap;text-overflow:ellipsis}.handsontable.listbox td.htDimmed{cursor:default;color:inherit;font-style:inherit}.handsontable.listbox .wtBorder{visibility:hidden}.handsontable.listbox tr td.current,.handsontable.listbox tr:hover td{background:#eee}.ht_clone_top{z-index:101}.ht_clone_left{z-index:102}.ht_clone_top_left_corner,.ht_clone_bottom_left_corner{z-index:103}.ht_clone_debug{z-index:103}.handsontable td.htSearchResult{background:#fcedd9;color:#583707}.htBordered{border-width:1px}.htBordered.htTopBorderSolid{border-top-style:solid;border-top-color:#000}.htBordered.htRightBorderSolid{border-right-style:solid;border-right-color:#000}.htBordered.htBottomBorderSolid{border-bottom-style:solid;border-bottom-color:#000}.htBordered.htLeftBorderSolid{border-left-style:solid;border-left-color:#000}.handsontable tbody tr th:nth-last-child(2){border-right:1px solid #CCC}.handsontable thead tr:nth-last-child(2) th.htGroupIndicatorContainer{border-bottom:1px solid #CCC;padding-bottom:5px}.ht_clone_top_left_corner thead tr th:nth-last-child(2){border-right:1px solid #CCC}.htCollapseButton{width:10px;height:10px;line-height:10px;text-align:center;border-radius:5px;border:1px solid #f3f3f3;-webkit-box-shadow:1px 1px 3px rgba(0,0,0,0.4);box-shadow:1px 1px 3px rgba(0,0,0,0.4);cursor:pointer;margin-bottom:3px;position:relative}.htCollapseButton:after{content:"";height:300%;width:1px;display:block;background:#ccc;margin-left:4px;position:absolute;bottom:10px}thead .htCollapseButton{right:5px;position:absolute;top:5px;background:#fff}thead .htCollapseButton:after{height:1px;width:700%;right:10px;top:4px}.handsontable tr th .htExpandButton{position:absolute;width:10px;height:10px;line-height:10px;text-align:center;border-radius:5px;border:1px solid #f3f3f3;-webkit-box-shadow:1px 1px 3px rgba(0,0,0,0.4);box-shadow:1px 1px 3px rgba(0,0,0,0.4);cursor:pointer;top:0;display:none}.handsontable thead tr th .htExpandButton{top:5px}.handsontable tr th .htExpandButton.clickable{display:block}.collapsibleIndicator{position:absolute;top:50%;transform:translate(0%,-50%);right:5px;border:1px solid #a6a6a6;line-height:10px;color:#222;border-radius:10px;font-size:10px;width:10px;height:10px;cursor:pointer;-webkit-box-shadow:0 0 0 6px rgba(238,238,238,1);-moz-box-shadow:0 0 0 6px rgba(238,238,238,1);box-shadow:0 0 0 6px rgba(238,238,238,1);background:#eee}.handsontable col.hidden{width:0!important}.handsontable table tr th.lightRightBorder{border-right:1px solid #e6e6e6}.handsontable tr.hidden,.handsontable tr.hidden td,.handsontable tr.hidden th{display:none}.ht_master,.ht_clone_left,.ht_clone_top,.ht_clone_bottom{overflow:hidden}.ht_master .wtHolder{overflow:auto}.ht_clone_left .wtHolder{overflow-x:hidden;overflow-y:auto}.ht_clone_top .wtHolder,.ht_clone_bottom .wtHolder{overflow-x:auto;overflow-y:hidden}.wtDebugHidden{display:none}.wtDebugVisible{display:block;-webkit-animation-duration:.5s;-webkit-animation-name:wtFadeInFromNone;animation-duration:.5s;animation-name:wtFadeInFromNone}@keyframes wtFadeInFromNone{0%{display:none;opacity:0}1%{display:block;opacity:0}100%{display:block;opacity:1}}@-webkit-keyframes wtFadeInFromNone{0%{display:none;opacity:0}1%{display:block;opacity:0}100%{display:block;opacity:1}}.handsontable.mobile,.handsontable.mobile .wtHolder{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-overflow-scrolling:touch}.htMobileEditorContainer{display:none;position:absolute;top:0;width:70%;height:54pt;background:#f8f8f8;border-radius:20px;border:1px solid #ebebeb;z-index:999;box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-text-size-adjust:none}.topLeftSelectionHandle:not(.ht_master .topLeftSelectionHandle),.topLeftSelectionHandle-HitArea:not(.ht_master .topLeftSelectionHandle-HitArea){z-index:9999}.topLeftSelectionHandle,.topLeftSelectionHandle-HitArea,.bottomRightSelectionHandle,.bottomRightSelectionHandle-HitArea{left:-10000px;top:-10000px}.htMobileEditorContainer.active{display:block}.htMobileEditorContainer .inputs{position:absolute;right:210pt;bottom:10pt;top:10pt;left:14px;height:34pt}.htMobileEditorContainer .inputs textarea{font-size:13pt;border:1px solid #a1a1a1;-webkit-appearance:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;position:absolute;left:14px;right:14px;top:0;bottom:0;padding:7pt}.htMobileEditorContainer .cellPointer{position:absolute;top:-13pt;height:0;width:0;left:30px;border-left:13pt solid transparent;border-right:13pt solid transparent;border-bottom:13pt solid #ebebeb}.htMobileEditorContainer .cellPointer.hidden{display:none}.htMobileEditorContainer .cellPointer:before{content:'';display:block;position:absolute;top:2px;height:0;width:0;left:-13pt;border-left:13pt solid transparent;border-right:13pt solid transparent;border-bottom:13pt solid #f8f8f8}.htMobileEditorContainer .moveHandle{position:absolute;top:10pt;left:5px;width:30px;bottom:0;cursor:move;z-index:9999}.htMobileEditorContainer .moveHandle:after{content:"..\a..\a..\a..";white-space:pre;line-height:10px;font-size:20pt;display:inline-block;margin-top:-8px;color:#ebebeb}.htMobileEditorContainer .positionControls{width:205pt;position:absolute;right:5pt;top:0;bottom:0}.htMobileEditorContainer .positionControls>div{width:50pt;height:100%;float:left}.htMobileEditorContainer .positionControls>div:after{content:" ";display:block;width:15pt;height:15pt;text-align:center;line-height:50pt}.htMobileEditorContainer .leftButton:after,.htMobileEditorContainer .rightButton:after,.htMobileEditorContainer .upButton:after,.htMobileEditorContainer .downButton:after{transform-origin:5pt 5pt;-webkit-transform-origin:5pt 5pt;margin:21pt 0 0 21pt}.htMobileEditorContainer .leftButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(-45deg)}.htMobileEditorContainer .leftButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .rightButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(135deg)}.htMobileEditorContainer .rightButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .upButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(45deg)}.htMobileEditorContainer .upButton:active:after{border-color:#cfcfcf}.htMobileEditorContainer .downButton:after{border-top:2px solid #288ffe;border-left:2px solid #288ffe;-webkit-transform:rotate(225deg)}.htMobileEditorContainer .downButton:active:after{border-color:#cfcfcf}.handsontable.hide-tween{-webkit-animation:opacity-hide .3s;animation:opacity-hide .3s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}.handsontable.show-tween{-webkit-animation:opacity-show .3s;animation:opacity-show .3s;animation-fill-mode:forwards;-webkit-animation-fill-mode:forwards}.htCommentCell{position:relative}.htCommentCell:after{content:'';position:absolute;top:0;right:0;border-left:6px solid transparent;border-top:6px solid black}.htComments{display:none;z-index:1059;position:absolute}.htCommentTextArea{box-shadow:rgba(0,0,0,0.117647) 0 1px 3px,rgba(0,0,0,0.239216) 0 1px 2px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:0;border-left:3px solid #ccc;background-color:#fff;width:215px;height:90px;font-size:12px;padding:5px;outline:0!important;-webkit-appearance:none}.htCommentTextArea:focus{box-shadow:rgba(0,0,0,0.117647) 0 1px 3px,rgba(0,0,0,0.239216) 0 1px 2px,inset 0 0 0 1px #5292f7;border-left:3px solid #5292f7}/*! 27 | * Handsontable ContextMenu 28 | */.htContextMenu{display:none;position:absolute;z-index:1060}.htContextMenu .ht_clone_top,.htContextMenu .ht_clone_left,.htContextMenu .ht_clone_corner,.htContextMenu .ht_clone_debug{display:none}.htContextMenu table.htCore{border:1px solid #ccc;border-bottom-width:2px;border-right-width:2px}.htContextMenu .wtBorder{visibility:hidden}.htContextMenu table tbody tr td{background:white;border-width:0;padding:4px 6px 0 6px;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.htContextMenu table tbody tr td:first-child{border:0}.htContextMenu table tbody tr td.htDimmed{font-style:normal;color:#323232}.htContextMenu table tbody tr td.current,.htContextMenu table tbody tr td.zeroclipboard-is-hover{background:#f3f3f3}.htContextMenu table tbody tr td.htSeparator{border-top:1px solid #bbb;height:0;padding:0;cursor:default}.htContextMenu table tbody tr td.htDisabled{color:#999;cursor:default}.htContextMenu table tbody tr td.htDisabled:hover{background:#fff;color:#999;cursor:default}.htContextMenu table tbody tr.htHidden{display:none}.htContextMenu table tbody tr td .htItemWrapper{margin-left:10px;margin-right:6px}.htContextMenu table tbody tr td div span.selected{margin-top:-2px;position:absolute;left:4px}.htContextMenu .ht_master .wtHolder{overflow:hidden}.htRowHeaders .ht_master.innerBorderLeft ~ .ht_clone_top_left_corner th:nth-child(2),.htRowHeaders .ht_master.innerBorderLeft ~ .ht_clone_left td:first-of-type{border-left:0 none}.handsontable .wtHider{position:relative}.handsontable.ht__manualColumnMove.after-selection--columns thead th.ht__highlight{cursor:move;cursor:-moz-grab;cursor:-webkit-grab;cursor:grab}.handsontable.ht__manualColumnMove.on-moving--columns,.handsontable.ht__manualColumnMove.on-moving--columns thead th.ht__highlight{cursor:move;cursor:-moz-grabbing;cursor:-webkit-grabbing;cursor:grabbing}.handsontable.ht__manualColumnMove.on-moving--columns .manualColumnResizer{display:none}.handsontable .ht__manualColumnMove--guideline,.handsontable .ht__manualColumnMove--backlight{position:absolute;height:100%;display:none}.handsontable .ht__manualColumnMove--guideline{background:#757575;width:2px;top:0;margin-left:-1px;z-index:105}.handsontable .ht__manualColumnMove--backlight{background:#343434;background:rgba(52,52,52,0.25);display:none;z-index:105;pointer-events:none}.handsontable.on-moving--columns.show-ui .ht__manualColumnMove--guideline,.handsontable.on-moving--columns .ht__manualColumnMove--backlight{display:block}.handsontable .wtHider{position:relative}.handsontable.ht__manualRowMove.after-selection--rows tbody th.ht__highlight{cursor:move;cursor:-moz-grab;cursor:-webkit-grab;cursor:grab}.handsontable.ht__manualRowMove.on-moving--rows,.handsontable.ht__manualRowMove.on-moving--rows tbody th.ht__highlight{cursor:move;cursor:-moz-grabbing;cursor:-webkit-grabbing;cursor:grabbing}.handsontable.ht__manualRowMove.on-moving--rows .manualRowResizer{display:none}.handsontable .ht__manualRowMove--guideline,.handsontable .ht__manualRowMove--backlight{position:absolute;width:100%;display:none}.handsontable .ht__manualRowMove--guideline{background:#757575;height:2px;left:0;margin-top:-1px;z-index:105}.handsontable .ht__manualRowMove--backlight{background:#343434;background:rgba(52,52,52,0.25);display:none;z-index:105;pointer-events:none}.handsontable.on-moving--rows.show-ui .ht__manualRowMove--guideline,.handsontable.on-moving--rows .ht__manualRowMove--backlight{display:block}/*! 29 | * Pikaday 30 | * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/ 31 | */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:before,.pika-single:after{content:" ";display:table}.pika-single:after{clear:both}.pika-single{*zoom:1}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;*display:inline;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:bold;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-prev,.pika-next{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5;*position:absolute;*top:0}.pika-prev:hover,.pika-next:hover{opacity:1}.pika-prev,.is-rtl .pika-next{float:left;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==');*left:0}.pika-next,.is-rtl .pika-prev{float:right;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=');*right:0}.pika-prev.is-disabled,.pika-next.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block;*display:inline}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table th,.pika-table td{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:bold;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:bold}.is-selected .pika-button{color:#fff;font-weight:bold;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#d5e9f7}.is-startrange .pika-button{color:#fff;background:#6cb31d;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:0;cursor:help} -------------------------------------------------------------------------------- /resources/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {%- block extrahead %} 4 | 5 | 6 | 9 | 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /rnd_requirements.txt: -------------------------------------------------------------------------------- 1 | https://github.com/chfw/lml/archive/master.zip 2 | https://github.com/pyexcel/pyexcel-io/archive/v0.4.x.zip 3 | https://github.com/pyexcel/pyexcel/archive/master.zip 4 | https://github.com/pyexcel/pyexcel-handsontable/archive/master.zip 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | from setuptools import setup, find_packages 3 | except ImportError: 4 | from ez_setup import use_setuptools 5 | use_setuptools() 6 | from setuptools import setup, find_packages 7 | import sys 8 | PY2 = sys.version_info[0] == 2 9 | PY26 = PY2 and sys.version_info[1] < 7 10 | 11 | NAME = 'sphinxcontrib-excel' 12 | AUTHOR = 'C.W.' 13 | VERSION = '0.0.2' 14 | EMAIL = 'wangc_2011@hotmail.com' 15 | LICENSE = 'New BSD' 16 | DESCRIPTION = ( 17 | 'Embed excel file as an excel-alike table into sphinx documentation.' + 18 | '' 19 | ) 20 | URL = 'https://github.com/pyexcel/sphinxcontrib-excel' 21 | DOWNLOAD_URL = '%s/archive/0.0.1.tar.gz' % URL 22 | FILES = ['README.rst', 'CHANGELOG.rst'] 23 | KEYWORDS = [ 24 | 'python' 25 | ] 26 | 27 | CLASSIFIERS = [ 28 | 'Topic :: Office/Business', 29 | 'Topic :: Utilities', 30 | 'Topic :: Software Development :: Libraries', 31 | 'Programming Language :: Python', 32 | 'Intended Audience :: Developers', 33 | 'Programming Language :: Python :: 2.6', 34 | 'Programming Language :: Python :: 2.7', 35 | 'Programming Language :: Python :: 3.3', 36 | 'Programming Language :: Python :: 3.4', 37 | 'Programming Language :: Python :: 3.5', 38 | 'Programming Language :: Python :: 3.6', 39 | 'License :: OSI Approved :: BSD License', 40 | ] 41 | 42 | INSTALL_REQUIRES = [ 43 | 'docutils', 44 | 'pyexcel>=0.5.0', 45 | 'pyexcel-xls>=0.4.0', 46 | 'pyexcel-odsr>=0.4.0', 47 | 'pyexcel-handsontable', 48 | 'sphinx', 49 | ] 50 | 51 | 52 | PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests']) 53 | EXTRAS_REQUIRE = { 54 | } 55 | 56 | 57 | def read_files(*files): 58 | """Read files into setup""" 59 | text = "" 60 | for single_file in files: 61 | content = read(single_file) 62 | text = text + content + "\n" 63 | return text 64 | 65 | 66 | def read(afile): 67 | """Read a file into setup""" 68 | with open(afile, 'r') as opened_file: 69 | content = filter_out_test_code(opened_file) 70 | content = "".join(list(content)) 71 | return content 72 | 73 | 74 | def filter_out_test_code(file_handle): 75 | found_test_code = False 76 | for line in file_handle.readlines(): 77 | if line.startswith('.. testcode:'): 78 | found_test_code = True 79 | continue 80 | if found_test_code is True: 81 | if line.startswith(' '): 82 | continue 83 | else: 84 | empty_line = line.strip() 85 | if len(empty_line) == 0: 86 | continue 87 | else: 88 | found_test_code = False 89 | yield line 90 | else: 91 | for keyword in ['|version|', '|today|']: 92 | if keyword in line: 93 | break 94 | else: 95 | yield line 96 | 97 | 98 | if __name__ == '__main__': 99 | setup( 100 | name=NAME, 101 | author=AUTHOR, 102 | version=VERSION, 103 | author_email=EMAIL, 104 | description=DESCRIPTION, 105 | url=URL, 106 | download_url=DOWNLOAD_URL, 107 | long_description=read_files(*FILES), 108 | license=LICENSE, 109 | keywords=KEYWORDS, 110 | extras_require=EXTRAS_REQUIRE, 111 | tests_require=['nose'], 112 | install_requires=INSTALL_REQUIRES, 113 | packages=PACKAGES, 114 | include_package_data=True, 115 | zip_safe=False, 116 | classifiers=CLASSIFIERS 117 | ) 118 | -------------------------------------------------------------------------------- /sphinx-doc-source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyexcel-renderers/sphinxcontrib-excel/09c56fcab83adf09ad98fc4e8cbdec756c8c5be5/sphinx-doc-source.png -------------------------------------------------------------------------------- /sphinx-doc-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyexcel-renderers/sphinxcontrib-excel/09c56fcab83adf09ad98fc4e8cbdec756c8c5be5/sphinx-doc-view.png -------------------------------------------------------------------------------- /sphinxcontrib-excel.yml: -------------------------------------------------------------------------------- 1 | overrides: "pyexcel.yaml" 2 | name: "sphinxcontrib-excel" 3 | misc: sphinxcontrib 4 | exclude_doctest: true 5 | nodocs: true 6 | version: 0.0.2 7 | current_version: 0.0.2 8 | release: 0.0.1 9 | include_doctest: false 10 | dependencies: 11 | - docutils 12 | - pyexcel>=0.5.0 13 | - pyexcel-xls>=0.4.0 14 | - pyexcel-odsr>=0.4.0 15 | - pyexcel-handsontable 16 | - sphinx 17 | description: Embed excel file as an excel-alike table into sphinx documentation. -------------------------------------------------------------------------------- /sphinxcontrib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sphinxcontrib 4 | ~~~~~~~~~~~~~ 5 | 6 | This package is a namespace package that contains all extensions 7 | distributed in the ``sphinx-contrib`` distribution 8 | 9 | :copyright: (c) 2017 by Onni Software Ltd. 10 | :license: New BSD, see LICENSE for details. 11 | """ 12 | 13 | __import__('pkg_resources').declare_namespace(__name__) 14 | -------------------------------------------------------------------------------- /sphinxcontrib/excel.py: -------------------------------------------------------------------------------- 1 | """ 2 | sphinxcontrib.excel 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Embed excel file as an excel-alike table into sphinx documentation. 6 | 7 | :copyright: (c) 2017 by Onni Software Ltd. 8 | :license: New BSD, see LICENSE for details. 9 | """ 10 | from docutils.parsers.rst import Directive 11 | from sphinx.util.i18n import search_image_for_language 12 | from docutils.parsers.rst import directives 13 | 14 | import docutils.core 15 | import pyexcel 16 | 17 | 18 | class PyexcelTable(Directive): 19 | required_arguments = 0 20 | optional_arguments = 1 21 | final_argument_whitespace = True 22 | has_content = True 23 | option_spec = { 24 | 'height': directives.nonnegative_int, 25 | 'width': directives.nonnegative_int 26 | } 27 | 28 | def run(self): 29 | env = self.state.document.settings.env 30 | width = 600 31 | height = None 32 | 33 | if len(self.arguments) > 0: 34 | fn = search_image_for_language(self.arguments[0], env) 35 | relfn, excel_file = env.relfn2path(fn) 36 | env.note_dependency(relfn) 37 | if self.options: 38 | width = self.options.get('width', 600) 39 | height = self.options.get('height') 40 | book = pyexcel.get_book(file_name=excel_file) 41 | else: 42 | content = '\n'.join(self.content) 43 | if '---pyexcel' in content: 44 | multiple_sheets = True 45 | else: 46 | multiple_sheets = False 47 | book = pyexcel.get_book(file_content='\n'.join(self.content), 48 | multiple_sheets=multiple_sheets, 49 | lineterminator='\n', 50 | file_type='csv') 51 | html = self.render_html(book, width, height) 52 | return [docutils.nodes.raw('', html, 53 | format='html')] 54 | 55 | def render_html(self, book, width, height): 56 | return book.get_handsontable_html( 57 | embed=True, width=width, height=height) 58 | 59 | 60 | class Pyecharts(PyexcelTable): 61 | 62 | def render_html(self, book, width, height): 63 | return book.get_echarts_html(embed=True, 64 | height=height, 65 | width=width) 66 | 67 | 68 | def setup(app): 69 | app.add_directive('pyexcel-table', PyexcelTable) 70 | app.add_directive('pyexcel-echarts', Pyecharts) 71 | return {'version': '0.0.1'} 72 | -------------------------------------------------------------------------------- /test.bat: -------------------------------------------------------------------------------- 1 | pip freeze 2 | nosetests --with-cov --cover-package sphinxcontrib --cover-package tests tests sphinxcontrib && flake8 . --exclude=.moban.d --builtins=unicode,xrange,long 3 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | pip freeze 2 | nosetests --with-cov --cover-package sphinxcontrib --cover-package tests tests sphinxcontrib && flake8 . --exclude=.moban.d --builtins=unicode,xrange,long 3 | -------------------------------------------------------------------------------- /tests/fixtures/test.csv: -------------------------------------------------------------------------------- 1 | 1,2,3 2 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | nose 2 | mock;python_version<"3" 3 | codecov 4 | coverage 5 | flake8 6 | pyexcel 7 | -------------------------------------------------------------------------------- /tests/test_excel.py: -------------------------------------------------------------------------------- 1 | import os 2 | from mock import MagicMock, patch 3 | from sphinxcontrib.excel import setup as s 4 | from nose.tools import eq_ 5 | 6 | """ 7 | When a directive implementation is being run, the directive class 8 | is instantiated, and the `run()` method is executed. During 9 | instantiation, the following instance variables are set: 10 | 11 | - ``name`` is the directive type or name (string). 12 | 13 | - ``arguments`` is the list of positional arguments (strings). 14 | 15 | - ``options`` is a dictionary mapping option names (strings) to 16 | values (type depends on option conversion functions; see 17 | `option_spec` above). 18 | 19 | - ``content`` is a list of strings, the directive content line by line. 20 | 21 | - ``lineno`` is the line number of the first line of the directive. 22 | 23 | - ``content_offset`` is the line offset of the first line of the 24 | content from 25 | the beginning of the current input. Used when initiating a nested parse. 26 | 27 | - ``block_text`` is a string containing the entire directive. 28 | 29 | - ``state`` is the state which called the directive function. 30 | 31 | - ``state_machine`` is the state machine which controls the state 32 | which called 33 | the directive function. 34 | """ 35 | 36 | 37 | def _verify_result(directive_run_result): 38 | content = str(directive_run_result[0]) 39 | assert '' in content 40 | assert 'var mydata = [[1, 2, 3]]' in content 41 | assert 'activateFirst' in content 42 | return content 43 | 44 | 45 | class TestTableDirective: 46 | def setUp(self): 47 | self.patcher = patch('sphinxcontrib.excel.search_image_for_language') 48 | fake_search = self.patcher.start() 49 | fake_search.return_value = '' 50 | 51 | def tearDown(self): 52 | self.patcher.stop() 53 | 54 | def test_pyexcel_table_directive(self): 55 | from sphinxcontrib.excel import PyexcelTable 56 | state = MagicMock() 57 | arguments = [os.path.join("tests", "fixtures", "test.csv")] 58 | state.document.settings.env.relfn2path.return_value = ( 59 | None, arguments[0]) 60 | directive = PyexcelTable('test', arguments, None, None, 61 | None, None, None, state, None) 62 | result = directive.run() 63 | _verify_result(result) 64 | 65 | def test_pyexcel_table_directive_with_width(self): 66 | from sphinxcontrib.excel import PyexcelTable 67 | state = MagicMock() 68 | arguments = [os.path.join("tests", "fixtures", "test.csv")] 69 | options = {'width': 400} 70 | state.document.settings.env.relfn2path.return_value = ( 71 | None, arguments[0]) 72 | directive = PyexcelTable('test', arguments, options, None, 73 | None, None, None, state, None) 74 | result = directive.run() 75 | content = _verify_result(result) 76 | # make sure with 400 takes effect 77 | assert '
    ' in content 78 | 79 | def test_pyexcel_table_with_content(self): 80 | from sphinxcontrib.excel import PyexcelTable 81 | state = MagicMock() 82 | content = [] 83 | with open(os.path.join("tests", "fixtures", "test.csv"), 'r') as f: 84 | content.append(f.readline()) 85 | directive = PyexcelTable('test', [], None, content, 86 | None, None, None, state, None) 87 | result = directive.run() 88 | _verify_result(result) 89 | 90 | def test_pyexcel_table_with_multiple_sheet_content(self): 91 | from sphinxcontrib.excel import PyexcelTable 92 | state = MagicMock() 93 | content = [ 94 | '---pyexcel:Sheet 1---', 95 | '1,2,3', 96 | '4,5,6', 97 | '7,8,9', 98 | '---pyexcel---', 99 | '---pyexcel:Sheet 2---', 100 | 'X,Y,Z', 101 | '1,2,3', 102 | '4,5,6', 103 | '---pyexcel---', 104 | '---pyexcel:Sheet 3---', 105 | 'O,P,Q', 106 | '3,2,1', 107 | '4,3,2', 108 | ] 109 | directive = PyexcelTable('test', [], None, content, 110 | None, None, None, state, None) 111 | result = directive.run() 112 | result = str(result[0]) 113 | assert '' in result 114 | assert '[["O", "P", "Q"], [3, 2, 1], [4, 3, 2]];' in result 115 | assert '[["X", "Y", "Z"], [1, 2, 3], [4, 5, 6]];' in result 116 | assert '[[1, 2, 3], [4, 5, 6], [7, 8, 9]];' in result 117 | assert 'activateFirst' in result 118 | 119 | 120 | def test_setup(): 121 | app = MagicMock() 122 | ret = s(app) 123 | eq_(ret, {'version': '0.0.1'}) 124 | --------------------------------------------------------------------------------