├── test ├── .gitignore ├── samples │ ├── text1.csv │ ├── toc.odt │ ├── image.png │ ├── image2.jpg │ ├── list.odt │ ├── meta.odt │ ├── note.odt │ ├── span_a.odt │ ├── bookmark.odt │ ├── example.odp │ ├── example.odt │ ├── variable.odt │ ├── base_shapes.odg │ ├── base_text.odt │ ├── frame_image.odp │ ├── span_style.odt │ ├── simple_table.ods │ ├── styled_table.ods │ ├── tracked_changes.odt │ ├── simple_table_named_range.ods │ └── rst2odt_sample.rst ├── test_scripts.sh ├── test_content.py ├── test_text.py ├── network_test.py ├── test_toc.py ├── test.py ├── test_span.py ├── test_section.py ├── test_image.py ├── use_case3.py ├── test_draw_page.py ├── use_case1.py ├── test_heading.py ├── test_manifest.py ├── test_xmlpart.py └── test_datatype.py ├── doc_make ├── static_in │ ├── README │ ├── LinLibertine_R.woff │ ├── banner-lpod_en.png │ └── lpod.css ├── sphinx-link.py ├── autodocs.rst ├── index.rst └── Makefile ├── README.md ├── contrib ├── archlinux │ ├── .gitignore │ └── PKGBUILD └── gentoo │ ├── README │ ├── lpod-python-0.9.0.ebuild │ ├── lpod-python-0.9.1.ebuild │ └── lpod-python-0.9.2.ebuild ├── documentation ├── html │ ├── _static │ │ ├── README │ │ ├── up.png │ │ ├── down.png │ │ ├── file.png │ │ ├── plus.png │ │ ├── comment.png │ │ ├── minus.png │ │ ├── ajax-loader.gif │ │ ├── down-pressed.png │ │ ├── up-pressed.png │ │ ├── banner-lpod_en.png │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── LinLibertine_R.woff │ │ ├── lpod.css │ │ └── pygments.css │ ├── objects.inv │ ├── _sources │ │ ├── autodocs │ │ │ ├── link.txt │ │ │ ├── list.txt │ │ │ ├── meta.txt │ │ │ ├── note.txt │ │ │ ├── span.txt │ │ │ ├── toc.txt │ │ │ ├── const.txt │ │ │ ├── frame.txt │ │ │ ├── image.txt │ │ │ ├── style.txt │ │ │ ├── table.txt │ │ │ ├── utils.txt │ │ │ ├── shapes.txt │ │ │ ├── smil.txt │ │ │ ├── styles.txt │ │ │ ├── cleaner.txt │ │ │ ├── content.txt │ │ │ ├── element.txt │ │ │ ├── heading.txt │ │ │ ├── rst2odt.txt │ │ │ ├── section.txt │ │ │ ├── xmlpart.txt │ │ │ ├── bookmark.txt │ │ │ ├── container.txt │ │ │ ├── datatype.txt │ │ │ ├── document.txt │ │ │ ├── draw_page.txt │ │ │ ├── manifest.txt │ │ │ ├── paragraph.txt │ │ │ ├── reference.txt │ │ │ ├── variable.txt │ │ │ ├── _version.txt │ │ │ ├── scriptutils.txt │ │ │ ├── paragraph_base.txt │ │ │ ├── tracked_changes.txt │ │ │ ├── _flags.txt │ │ │ ├── future.txt │ │ │ ├── legacy.txt │ │ │ └── experimental.txt │ │ ├── autodocs.txt │ │ └── index.txt │ └── search.html └── former_releases_notices │ ├── RELEASE-0.9.1 │ ├── RELEASE-0.8 │ ├── RELEASE-0.9.2 │ └── RELEASE-0.9.0 ├── RELEASE-1.1.0 ├── lpod ├── templates │ ├── text.ott │ ├── drawing.otg │ ├── lpod_styles.odt │ ├── spreadsheet.ots │ ├── presentation.otp │ ├── test_template.ott │ ├── test_template.py │ └── namespaces.xml ├── _version.py ├── future.py ├── legacy.py ├── experimental.py ├── span.py ├── _flags.py ├── __init__.py ├── bookmark.py ├── section.py ├── image.py ├── cleaner.py ├── scriptutils.py ├── content.py ├── heading.py ├── link.py ├── smil.py ├── xmlpart.py ├── manifest.py └── const.py ├── MANIFEST.in ├── .gitignore ├── INSTALL ├── license.txt ├── README ├── scripts ├── lpod-test.py ├── lpod-clean.py ├── lpod-folder.py ├── lpod-diff.py ├── lpod-meta.py ├── lpod-mm2odt.py └── lpod-highlight.py ├── setup.py ├── release.py └── scriptutils.py /test/.gitignore: -------------------------------------------------------------------------------- 1 | python 2 | test_output 3 | -------------------------------------------------------------------------------- /test/samples/text1.csv: -------------------------------------------------------------------------------- 1 | "foo1","foo2" 2 | "1","2" 3 | -------------------------------------------------------------------------------- /doc_make/static_in/README: -------------------------------------------------------------------------------- 1 | This directory is compulsory 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/README.md -------------------------------------------------------------------------------- /contrib/archlinux/.gitignore: -------------------------------------------------------------------------------- 1 | src 2 | pkg 3 | *.tar.gz 4 | *.tar.xz 5 | -------------------------------------------------------------------------------- /documentation/html/_static/README: -------------------------------------------------------------------------------- 1 | This directory is compulsory 2 | 3 | -------------------------------------------------------------------------------- /RELEASE-1.1.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/RELEASE-1.1.0 -------------------------------------------------------------------------------- /test/samples/toc.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/toc.odt -------------------------------------------------------------------------------- /contrib/gentoo/README: -------------------------------------------------------------------------------- 1 | You need the app-doc/lpod-docs ebuild if you enable 'doc' USE flag. 2 | 3 | -------------------------------------------------------------------------------- /lpod/templates/text.ott: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/text.ott -------------------------------------------------------------------------------- /test/samples/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/image.png -------------------------------------------------------------------------------- /test/samples/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/image2.jpg -------------------------------------------------------------------------------- /test/samples/list.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/list.odt -------------------------------------------------------------------------------- /test/samples/meta.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/meta.odt -------------------------------------------------------------------------------- /test/samples/note.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/note.odt -------------------------------------------------------------------------------- /test/samples/span_a.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/span_a.odt -------------------------------------------------------------------------------- /test/samples/bookmark.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/bookmark.odt -------------------------------------------------------------------------------- /test/samples/example.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/example.odp -------------------------------------------------------------------------------- /test/samples/example.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/example.odt -------------------------------------------------------------------------------- /test/samples/variable.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/variable.odt -------------------------------------------------------------------------------- /lpod/templates/drawing.otg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/drawing.otg -------------------------------------------------------------------------------- /test/samples/base_shapes.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/base_shapes.odg -------------------------------------------------------------------------------- /test/samples/base_text.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/base_text.odt -------------------------------------------------------------------------------- /test/samples/frame_image.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/frame_image.odp -------------------------------------------------------------------------------- /test/samples/span_style.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/span_style.odt -------------------------------------------------------------------------------- /documentation/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/objects.inv -------------------------------------------------------------------------------- /lpod/templates/lpod_styles.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/lpod_styles.odt -------------------------------------------------------------------------------- /lpod/templates/spreadsheet.ots: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/spreadsheet.ots -------------------------------------------------------------------------------- /test/samples/simple_table.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/simple_table.ods -------------------------------------------------------------------------------- /test/samples/styled_table.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/styled_table.ods -------------------------------------------------------------------------------- /documentation/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/up.png -------------------------------------------------------------------------------- /lpod/templates/presentation.otp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/presentation.otp -------------------------------------------------------------------------------- /lpod/templates/test_template.ott: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/lpod/templates/test_template.ott -------------------------------------------------------------------------------- /test/samples/tracked_changes.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/tracked_changes.odt -------------------------------------------------------------------------------- /documentation/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/down.png -------------------------------------------------------------------------------- /documentation/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/file.png -------------------------------------------------------------------------------- /documentation/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/plus.png -------------------------------------------------------------------------------- /doc_make/static_in/LinLibertine_R.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/doc_make/static_in/LinLibertine_R.woff -------------------------------------------------------------------------------- /doc_make/static_in/banner-lpod_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/doc_make/static_in/banner-lpod_en.png -------------------------------------------------------------------------------- /documentation/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/comment.png -------------------------------------------------------------------------------- /documentation/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/minus.png -------------------------------------------------------------------------------- /documentation/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /documentation/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/down-pressed.png -------------------------------------------------------------------------------- /documentation/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/up-pressed.png -------------------------------------------------------------------------------- /test/samples/simple_table_named_range.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/test/samples/simple_table_named_range.ods -------------------------------------------------------------------------------- /documentation/html/_static/banner-lpod_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/banner-lpod_en.png -------------------------------------------------------------------------------- /documentation/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/comment-bright.png -------------------------------------------------------------------------------- /documentation/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/comment-close.png -------------------------------------------------------------------------------- /documentation/html/_static/LinLibertine_R.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lpod/lpod-python/HEAD/documentation/html/_static/LinLibertine_R.woff -------------------------------------------------------------------------------- /doc_make/sphinx-link.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pkg_resources import load_entry_point 3 | 4 | entry_point = load_entry_point('Sphinx>=0.6.1', 'console_scripts', 5 | 'sphinx-build') 6 | sys.exit(entry_point()) 7 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/link.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.link` 2 | ############################################## 3 | .. automodule:: lpod.link 4 | :synopsis: Lpod link module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/list.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.list` 2 | ############################################## 3 | .. automodule:: lpod.list 4 | :synopsis: Lpod list module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/meta.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.meta` 2 | ############################################## 3 | .. automodule:: lpod.meta 4 | :synopsis: Lpod meta module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/note.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.note` 2 | ############################################## 3 | .. automodule:: lpod.note 4 | :synopsis: Lpod note module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/span.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.span` 2 | ############################################## 3 | .. automodule:: lpod.span 4 | :synopsis: Lpod span module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/toc.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.toc` 2 | ############################################## 3 | .. automodule:: lpod.toc 4 | :synopsis: Lpod toc module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/const.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.const` 2 | ############################################## 3 | .. automodule:: lpod.const 4 | :synopsis: Lpod const module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/frame.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.frame` 2 | ############################################## 3 | .. automodule:: lpod.frame 4 | :synopsis: Lpod frame module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/image.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.image` 2 | ############################################## 3 | .. automodule:: lpod.image 4 | :synopsis: Lpod image module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/style.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.style` 2 | ############################################## 3 | .. automodule:: lpod.style 4 | :synopsis: Lpod style module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/table.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.table` 2 | ############################################## 3 | .. automodule:: lpod.table 4 | :synopsis: Lpod table module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/utils.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.utils` 2 | ############################################## 3 | .. automodule:: lpod.utils 4 | :synopsis: Lpod utils module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/shapes.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.shapes` 2 | ############################################## 3 | .. automodule:: lpod.shapes 4 | :synopsis: Lpod shapes module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/smil.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.smil` 2 | ############################################## 3 | .. automodule:: lpod.smil 4 | :synopsis: Implementation of SMIL 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/styles.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.styles` 2 | ############################################## 3 | .. automodule:: lpod.styles 4 | :synopsis: Lpod styles module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/cleaner.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.cleaner` 2 | ############################################## 3 | .. automodule:: lpod.cleaner 4 | :synopsis: Lpod cleaner module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/content.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.content` 2 | ############################################## 3 | .. automodule:: lpod.content 4 | :synopsis: Lpod content module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/element.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.element` 2 | ############################################## 3 | .. automodule:: lpod.element 4 | :synopsis: Lpod element module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/heading.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.heading` 2 | ############################################## 3 | .. automodule:: lpod.heading 4 | :synopsis: Lpod heading module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/rst2odt.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.rst2odt` 2 | ############################################## 3 | .. automodule:: lpod.rst2odt 4 | :synopsis: Lpod rst2odt module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/section.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.section` 2 | ############################################## 3 | .. automodule:: lpod.section 4 | :synopsis: Lpod section module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/xmlpart.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.xmlpart` 2 | ############################################## 3 | .. automodule:: lpod.xmlpart 4 | :synopsis: Lpod xmlpart module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/bookmark.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.bookmark` 2 | ############################################## 3 | .. automodule:: lpod.bookmark 4 | :synopsis: Lpod bookmark module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/container.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.container` 2 | ############################################## 3 | .. automodule:: lpod.container 4 | :synopsis: Lpod container module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/datatype.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.datatype` 2 | ############################################## 3 | .. automodule:: lpod.datatype 4 | :synopsis: Lpod datatype module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/document.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.document` 2 | ############################################## 3 | .. automodule:: lpod.document 4 | :synopsis: Lpod document module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/draw_page.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.draw_page` 2 | ############################################## 3 | .. automodule:: lpod.draw_page 4 | :synopsis: Lpod draw_page module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/manifest.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.manifest` 2 | ############################################## 3 | .. automodule:: lpod.manifest 4 | :synopsis: Lpod manifest module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/paragraph.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.paragraph` 2 | ############################################## 3 | .. automodule:: lpod.paragraph 4 | :synopsis: Lpod paragraph module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/reference.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.reference` 2 | ############################################## 3 | .. automodule:: lpod.reference 4 | :synopsis: Lpod reference module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/variable.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.variable` 2 | ############################################## 3 | .. automodule:: lpod.variable 4 | :synopsis: Lpod variable module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/_version.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod._version` 2 | ############################################## 3 | .. automodule:: lpod._version 4 | :synopsis: 5 | version. 6 | 7 | :show-inheritance: 8 | :members: 9 | :undoc-members: 10 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/scriptutils.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.scriptutils` 2 | ############################################## 3 | .. automodule:: lpod.scriptutils 4 | :synopsis: Lpod scriptutils module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/paragraph_base.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.paragraph_base` 2 | ############################################## 3 | .. automodule:: lpod.paragraph_base 4 | :synopsis: Lpod paragraph_base module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/tracked_changes.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.tracked_changes` 2 | ############################################## 3 | .. automodule:: lpod.tracked_changes 4 | :synopsis: Lpod tracked_changes module 5 | :show-inheritance: 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/_flags.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod._flags` 2 | ############################################## 3 | .. automodule:: lpod._flags 4 | :synopsis: 5 | Options flags management for Lpod. Internal use of the library. 6 | 7 | :show-inheritance: 8 | :members: 9 | :undoc-members: 10 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/future.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.future` 2 | ############################################## 3 | .. automodule:: lpod.future 4 | :synopsis: 5 | Loading his module activate the 'future' compatibility mode (aka versions 1.1+) 6 | 7 | :show-inheritance: 8 | :members: 9 | :undoc-members: 10 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/legacy.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.legacy` 2 | ############################################## 3 | .. automodule:: lpod.legacy 4 | :synopsis: 5 | Loading his module activate the 'legacy' compatibility mode (aka versions 0.9.x) 6 | 7 | :show-inheritance: 8 | :members: 9 | :undoc-members: 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include INSTALL 2 | include *.txt *.py *.md 3 | include RELEASE* 4 | recursive-include contrib * 5 | recursive-include doc_make * 6 | recursive-include documentation * 7 | recursive-include test *.py *.od? *.txt *.csv *.zip *.xml 8 | prune doc_make/build 9 | prune doc_make/autodocs 10 | prune test/test_output 11 | 12 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs/experimental.txt: -------------------------------------------------------------------------------- 1 | :mod:`lpod.experimental` 2 | ############################################## 3 | .. automodule:: lpod.experimental 4 | :synopsis: 5 | Loading his module activate the 'experimental' compatibility mode 6 | (aka experimental features) 7 | 8 | :show-inheritance: 9 | :members: 10 | :undoc-members: 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MANIFEST 2 | version.txt 3 | python_path.txt 4 | build 5 | doc_make/autodocs 6 | dist 7 | test/trash 8 | *.swp 9 | *.py[co] 10 | .buildinfo 11 | 12 | # Packages 13 | *.egg 14 | *.egg-info 15 | dist 16 | build 17 | eggs 18 | parts 19 | bin 20 | var 21 | sdist 22 | develop-eggs 23 | .installed.cfg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | 28 | # Unit test / coverage reports 29 | .coverage 30 | .tox 31 | 32 | # OS X 33 | .DS_Store 34 | 35 | #Translations 36 | *.mo 37 | 38 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Install Dependencies: 2 | - python >= 2.6: http://www.python.org/ 3 | - python setuptools: https://pypi.python.org/pypi/setuptools 4 | - lxml >= 2.0: http://codespeak.net/lxml/ 5 | - recommanded : Python Imaging Library (PIL) 6 | 7 | Dependencies Packages: 8 | - Debian: 9 | python-setuptools 10 | python-lxml 11 | python-imaging 12 | - CentOS: 13 | python-setuptools 14 | python-lxml 15 | python-imaging 16 | 17 | Installation: 18 | $ sudo python setup.py install 19 | -------------------------------------------------------------------------------- /contrib/gentoo/lpod-python-0.9.0.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2009 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v2 3 | # $Header: $ 4 | 5 | NEED_PYTHON=2.6 6 | inherit distutils 7 | 8 | DESCRIPTION="languages & platforms OpenDocument - Python library" 9 | HOMEPAGE="http://lpod-project.net" 10 | SRC_URI="http://download.lpod-project.net/${PN}/${P}.tar.gz" 11 | 12 | LICENSE="GPL-3 Apache-2.0" 13 | SLOT="0" 14 | KEYWORDS="~amd64 ~x86" 15 | IUSE="doc" 16 | 17 | DEPEND="" 18 | RDEPEND=">=dev-python/lxml-2.0 19 | >=dev-python/pygobject-2.16.1 20 | doc? ( =app-doc/lpod-docs-${PV} )" 21 | 22 | -------------------------------------------------------------------------------- /contrib/gentoo/lpod-python-0.9.1.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2009 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v2 3 | # $Header: $ 4 | 5 | NEED_PYTHON=2.6 6 | inherit distutils 7 | 8 | DESCRIPTION="languages & platforms OpenDocument - Python library" 9 | HOMEPAGE="http://lpod-project.net" 10 | SRC_URI="http://download.lpod-project.net/${PN}/${P}.tar.gz" 11 | 12 | LICENSE="GPL-3 Apache-2.0" 13 | SLOT="0" 14 | KEYWORDS="~amd64 ~x86" 15 | IUSE="doc" 16 | 17 | DEPEND="" 18 | RDEPEND=">=dev-python/lxml-2.0 19 | >=dev-python/pygobject-2.16.1 20 | doc? ( =app-doc/lpod-docs-${PV} )" 21 | 22 | -------------------------------------------------------------------------------- /contrib/gentoo/lpod-python-0.9.2.ebuild: -------------------------------------------------------------------------------- 1 | # Copyright 1999-2009 Gentoo Foundation 2 | # Distributed under the terms of the GNU General Public License v2 3 | # $Header: $ 4 | 5 | NEED_PYTHON=2.6 6 | inherit distutils 7 | 8 | DESCRIPTION="languages & platforms OpenDocument - Python library" 9 | HOMEPAGE="http://lpod-project.net" 10 | SRC_URI="http://download.lpod-project.net/${PN}/${P}.tar.gz" 11 | 12 | LICENSE="GPL-3 Apache-2.0" 13 | SLOT="0" 14 | KEYWORDS="~amd64 ~x86" 15 | IUSE="doc" 16 | 17 | DEPEND="" 18 | RDEPEND=">=dev-python/lxml-2.0 19 | >=dev-python/pygobject-2.16.1 20 | doc? ( =app-doc/lpod-docs-${PV} )" 21 | 22 | -------------------------------------------------------------------------------- /contrib/archlinux/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Hervé Cauwelier 2 | # Published at http://aur.archlinux.org/packages.php?ID=34271 3 | 4 | pkgname=python-lpod 5 | pkgver=0.9.3 6 | pkgrel=1 7 | pkgdesc="Languages & Platforms OpenDocument: Python implementation" 8 | arch=('any') 9 | license=('GPL3' 'APACHE2') 10 | url="http://www.lpod-project.net/" 11 | depends=('python-lxml' 'pygobject') 12 | source=("http://download.lpod-project.net/lpod-python/lpod-python-$pkgver.tar.gz") 13 | md5sums=('9a5425245c9cad1ca0f72c0f50833824') 14 | 15 | build() { 16 | cd "${srcdir}/lpod-python-$pkgver" 17 | python2 setup.py install --root="${pkgdir}" || return 1 18 | } 19 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | License of lpod-python 2 | ====================== 3 | 4 | Lpod is free software; you can redistribute it and/or modify it under 5 | the terms of either: 6 | 7 | a) the GNU General Public License as published by the Free Software 8 | Foundation, either version 3 of the License, or (at your option) 9 | any later version. 10 | Lpod is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | You should have received a copy of the GNU General Public License 15 | along with Lpod. If not, see . 16 | 17 | b) the Apache License, Version 2.0 (the "License"); 18 | you may not use this file except in compliance with the License. 19 | You may obtain a copy of the License at 20 | http://www.apache.org/licenses/LICENSE-2.0 21 | 22 | -------------------------------------------------------------------------------- /lpod/_version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | """ 28 | version. 29 | """ 30 | 31 | __version_info__ = (1, 1, 7) 32 | __version__ = '.'.join(str(i) for i in __version_info__) 33 | 34 | -------------------------------------------------------------------------------- /lpod/future.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | """ 28 | Loading his module activate the 'future' compatibility mode (aka versions 1.1+) 29 | """ 30 | 31 | import _flags 32 | 33 | _flags.future.set(True) 34 | -------------------------------------------------------------------------------- /lpod/legacy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | """ 28 | Loading his module activate the 'legacy' compatibility mode (aka versions 0.9.x) 29 | """ 30 | 31 | import _flags 32 | 33 | _flags.legacy.set(True) 34 | 35 | -------------------------------------------------------------------------------- /lpod/experimental.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | """ 28 | Loading his module activate the 'experimental' compatibility mode 29 | (aka experimental features) 30 | """ 31 | 32 | import _flags 33 | 34 | _flags.experimental.set(True) 35 | -------------------------------------------------------------------------------- /doc_make/autodocs.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 2 | 3 | Authors: David Versmisse 4 | Hervé Cauwelier 5 | Jerome Dumonteil 6 | 7 | This file is part of Lpod (see: http://lpod-project.net). 8 | Lpod is free software; you can redistribute it and/or modify it under 9 | the terms of either: 10 | 11 | a) the GNU General Public License as published by the Free Software 12 | Foundation, either version 3 of the License, or (at your option) 13 | any later version. 14 | Lpod is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | You should have received a copy of the GNU General Public License 19 | along with Lpod. If not, see . 20 | 21 | b) the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | http://www.apache.org/licenses/LICENSE-2.0 25 | 26 | 27 | lpod-python 28 | =========== 29 | 30 | .. toctree:: 31 | :glob: 32 | :maxdepth: 1 33 | 34 | autodocs/* 35 | -------------------------------------------------------------------------------- /lpod/templates/test_template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | 4 | # Import from the Standard Library 5 | from datetime import date 6 | from os import remove 7 | from os.path import exists 8 | from sys import argv, stderr, exit 9 | 10 | # Import from lpod 11 | from lpod.document import odf_new_document 12 | from lpod.span import odf_create_span 13 | from lpod.template import stl_odf 14 | 15 | 16 | def get_namespace(homme=False): 17 | return {u"titre": u"Test de STL no 1", 18 | u"date": date.today().strftime(u"%d/%m/%Y"), 19 | u"homme": homme, 20 | u"genre": u"M." if homme else u"Mme", 21 | u"nom": u"Michu", 22 | u"enum1": {'label': u"Revenu", 'value': 1234.56}, 23 | u"enum2": {'label': u"Âge", 'value': 65}, 24 | u"couleur": u"rouge", 25 | u"gras": u"gras comme un moine", 26 | u"élément": odf_create_span(u"élément", style='T2')} 27 | 28 | 29 | if __name__ == '__main__': 30 | try: 31 | output = argv[1] 32 | except IndexError: 33 | print >>stderr, "Usage: %s " % argv[0] 34 | exit(1) 35 | document = odf_new_document('test_template.ott') 36 | stl_odf(document, get_namespace()) 37 | if exists(output): 38 | remove(output) 39 | document.save(output) 40 | print 'Document "%s" generated.' % output 41 | -------------------------------------------------------------------------------- /documentation/html/_sources/autodocs.txt: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 2 | 3 | Authors: David Versmisse 4 | Hervé Cauwelier 5 | Jerome Dumonteil 6 | 7 | This file is part of Lpod (see: http://lpod-project.net). 8 | Lpod is free software; you can redistribute it and/or modify it under 9 | the terms of either: 10 | 11 | a) the GNU General Public License as published by the Free Software 12 | Foundation, either version 3 of the License, or (at your option) 13 | any later version. 14 | Lpod is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | You should have received a copy of the GNU General Public License 19 | along with Lpod. If not, see . 20 | 21 | b) the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | http://www.apache.org/licenses/LICENSE-2.0 25 | 26 | 27 | lpod-python 28 | =========== 29 | 30 | .. toctree:: 31 | :glob: 32 | :maxdepth: 1 33 | 34 | autodocs/* 35 | -------------------------------------------------------------------------------- /lpod/span.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2013 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # Jerome Dumonteil 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | ######## 29 | ######## 30 | ######## Content moved in paragraph.py 31 | ######## 32 | ######## 33 | 34 | from paragraph import _odf_create_span 35 | 36 | odf_create_span = _odf_create_span 37 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | lpod-python 2 | =========== 3 | 4 | Python library implementing the ISO/IEC 26300 OpenDocument Format standard. 5 | 6 | This library is the python implementation of the lpOD Project (Languages & 7 | Platforms OpenDocument, definition of a Free Software API implementing the 8 | ISO/IEC 26300 standard). 9 | 10 | 11 | This branch is the 'current' branch, aiming to be the next stable version. 12 | 13 | Maintained branches are: 14 | 15 | - legacy : compatible with 0.9x versions 16 | - current : next stable version 17 | - master : currently, master = current 18 | 19 | The most recent version of this package is there: 20 | 21 | https://github.com/lpod/lpod-python 22 | 23 | How to get the code with git: 24 | 25 | git clone git://github.com/lpod/lpod-python.git 26 | git checkout current 27 | 28 | 29 | Documentation: see the ./documentation/html folder. 30 | 31 | 32 | Some usefull packages for the use of the lpod-python library: 33 | 34 | 35 | - Programming recipes for the lpod-python library: 36 | 37 | https://github.com/lpod/lpod-python-recipes 38 | 39 | 40 | - Lpod global documentation (currently inaccurate): 41 | 42 | https://github.com/lpod/lpod-docs 43 | 44 | 45 | 46 | About the Lpod Project, see: 47 | 48 | http://lpod-project.net 49 | 50 | 51 | Architect: Jean-Marie Gouarné 52 | 53 | Coordinator: Luis Belmar-Letelier 54 | -------------------------------------------------------------------------------- /test/test_scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # quick test of scripts 3 | 4 | err=0 5 | tot=0 6 | p="python ../scripts" 7 | s="samples" 8 | alias rm='/bin/rm' 9 | 10 | 11 | lp_clean () { $p/lpod-clean.py $s/bookmark.odt /dev/null ; } 12 | lp_clean () { $p/lpod-clean.py $s/example.odt /dev/null ; } 13 | lp_convert () { $p/lpod-convert.py $s/simple_table.ods a.odt && rm a.odt ;} 14 | lp_convert2 () { $p/lpod-convert.py $s/simple_table.ods a.csv && rm a.csv ;} 15 | lp_convert3 () { $p/lpod-convert.py $s/example.odt a.txt && rm a.txt ;} 16 | lp_convert4 () { $p/lpod-convert.py $s/example.odp a.html && rm a.html ;} 17 | lp_diff () { $p/lpod-diff.py $s/example.odt $s/base_text.odt ;} 18 | lp_folder () { $p/lpod-folder.py $s/example.odt && rm -r $s/example.odt.folder ;} 19 | lp_high () { $p/lpod-highlight.py -o a.odt -b $s/example.odt First && rm a.odt ;} 20 | lp_merge () { $p/lpod-merge.py -o a.odt $s/base_text.odt $s/example.odt && rm a.odt ;} 21 | lp_meta () { $p/lpod-meta.py $s/meta.odt ;} 22 | lp_show () { $p/lpod-show.py $s/bookmark.odt ;} 23 | lp_show2 () { $p/lpod-show.py $s/example.odp ;} 24 | lp_style () { $p/lpod-style.py $s/example.odt ;} 25 | 26 | 27 | tests=" 28 | lp_clean 29 | lp_convert 30 | lp_convert2 31 | lp_convert3 32 | lp_convert4 33 | lp_diff 34 | lp_folder 35 | lp_high 36 | lp_merge 37 | lp_meta 38 | lp_show 39 | lp_show2 40 | lp_style 41 | " 42 | 43 | 44 | for t in $tests ; do 45 | let tot++ 46 | echo -en "$t :" 47 | $t &> /dev/null && echo " passed." || { echo " failed !"; let err++ ; } 48 | #$t && echo " passed." || { echo " failed !"; let err++ ; } 49 | done 50 | echo 51 | echo "------------------------------------------" 52 | echo "total scripts: $tot, failed scripts: $err" 53 | echo "------------------------------------------" 54 | -------------------------------------------------------------------------------- /documentation/former_releases_notices/RELEASE-0.9.1: -------------------------------------------------------------------------------- 1 | ====================== 2 | LpOD 0.9.1 aka Granada 3 | ====================== 4 | 5 | lpOD -- languages & platforms OpenDocument. 6 | Definition of a Free Software API implementing the ISO/IEC 26300 standard. 7 | Development, for higher level use cases, in Python, Perl and Ruby languages. 8 | of a top-down oriented API. 9 | 10 | This release has seen Restructured Text support much improved, and a Gentoo 11 | ebuild was contributed. Packaging of lpOD was a bit improved too and now it's 12 | publised on Pypi [#]_. 13 | 14 | .. [#] http://pypi.python.org/pypi/lpod-python 15 | 16 | A effort was made to remove ODF 1.2 traces from the templates, because lpOD 17 | targets ODF 1.1 for now. ODF 1.2 is not published yet. 18 | 19 | - Web: http://lpod-project.net 20 | - Documentation: http://docs.lpod-project.net 21 | - IRC: irc://irc.freenode.org/lpod 22 | 23 | Low-level API 24 | ============= 25 | 26 | - "get_style" and "get_style_list" callable from any element. 27 | - "odf_container.get_contents" renamed to "get_parts" 28 | - "odf_document.get_files" renamed to "get_parts" 29 | - "odf_document.get_file_data" renamed to "get_part" 30 | 31 | High-level API 32 | ============== 33 | 34 | - To get a style by its display name, call:: 35 | 36 | context.get_style(family, display_name=u"My Style") 37 | 38 | It was previously a boolean flag. 39 | 40 | - In meta part, "(g|s)et_keyword" were renamed to "(g|s)et_keywords" to 41 | illustrate the possibility of assigning several keywords. ;-) But it still 42 | takes a single unicode string. 43 | 44 | - In meta part, added "(g|s)et_comments" as an alias to "(g|s)et_description" 45 | because some desktop applications call them like this. 46 | 47 | - Table cells gained a "(g|s)et_cell_formula" method. Yes, formulas begin to be 48 | taken into consideration! 49 | -------------------------------------------------------------------------------- /lpod/_flags.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2012 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | """ 28 | Options flags management for Lpod. Internal use of the library. 29 | """ 30 | 31 | 32 | # some singleton boolean frame 33 | # default is False 34 | class Flag: 35 | """ 36 | A boolean object. 37 | """ 38 | def __init__(self, value=False): 39 | self.__flag = bool(value) 40 | 41 | def set(self, value): 42 | self.__flag = bool(value) 43 | 44 | def __repr__(self): 45 | return ' %s' % self.__flag 46 | 47 | def __bool__(self): 48 | return self.__flag 49 | 50 | __nonzero__ = __bool__ 51 | 52 | 53 | 54 | legacy = Flag(False) 55 | 56 | future = Flag(False) 57 | 58 | experimental = Flag(False) 59 | -------------------------------------------------------------------------------- /lpod/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # Hervé Cauwelier 7 | # Romain Gauthier 8 | # 9 | # This file is part of Lpod (see: http://lpod-project.net). 10 | # Lpod is free software; you can redistribute it and/or modify it under 11 | # the terms of either: 12 | # 13 | # a) the GNU General Public License as published by the Free Software 14 | # Foundation, either version 3 of the License, or (at your option) 15 | # any later version. 16 | # Lpod is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # You should have received a copy of the GNU General Public License 21 | # along with Lpod. If not, see . 22 | # 23 | # b) the Apache License, Version 2.0 (the "License"); 24 | # you may not use this file except in compliance with the License. 25 | # You may obtain a copy of the License at 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | 29 | # Import from lpod 30 | from utils import _get_abspath 31 | from _version import __version__ 32 | 33 | __installation_path__ = _get_abspath('') 34 | 35 | 36 | # Constants at the first level 37 | from const import * 38 | 39 | 40 | # Register element classes 41 | import draw_page 42 | import frame 43 | import heading 44 | import list 45 | import note 46 | import paragraph 47 | import section 48 | import shapes 49 | import span 50 | import style 51 | import table 52 | import toc 53 | import tracked_changes 54 | 55 | # Silent pyflakes 56 | draw_page, frame, heading, list, note, paragraph, section, shapes, span, 57 | style, table, toc, tracked_changes 58 | -------------------------------------------------------------------------------- /lpod/bookmark.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from lpod 28 | from element import odf_create_element 29 | 30 | 31 | def odf_create_bookmark(name): 32 | """ 33 | Arguments: 34 | 35 | name -- unicode 36 | """ 37 | element = odf_create_element('text:bookmark') 38 | element.set_attribute('text:name', name) 39 | return element 40 | 41 | 42 | 43 | def odf_create_bookmark_start(name): 44 | """ 45 | Arguments: 46 | 47 | name -- unicode 48 | """ 49 | element = odf_create_element('text:bookmark-start') 50 | element.set_attribute('text:name', name) 51 | return element 52 | 53 | 54 | 55 | def odf_create_bookmark_end(name): 56 | """ 57 | Arguments: 58 | 59 | name -- unicode 60 | """ 61 | element = odf_create_element('text:bookmark-end') 62 | element.set_attribute('text:name', name) 63 | return element 64 | -------------------------------------------------------------------------------- /scripts/lpod-test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the standard library 29 | from optparse import OptionParser 30 | from sys import exit 31 | 32 | # Import from lpod 33 | from lpod import __version__ 34 | from lpod.release import _run_command 35 | 36 | 37 | if __name__ == "__main__": 38 | # Options initialisation 39 | usage = "%prog " 40 | description = ("Validate an ODF document thanks to the ODFPY project " 41 | "cf http://odfpy.forge.osor.eu/") 42 | parser = OptionParser(usage, version=__version__, 43 | description=description) 44 | # Parse options 45 | options, args = parser.parse_args() 46 | 47 | # Document 48 | if len(args) != 1: 49 | parser.print_help() 50 | exit(1) 51 | document = args[0] 52 | 53 | # Finish me :-) 54 | print _run_command(["odflint", document]) 55 | -------------------------------------------------------------------------------- /lpod/templates/namespaces.xml: -------------------------------------------------------------------------------- 1 | 2 | %s 35 | -------------------------------------------------------------------------------- /scripts/lpod-clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the standard library 29 | from optparse import OptionParser 30 | from sys import exit 31 | 32 | # Import from lpod 33 | from lpod import __version__ 34 | from lpod.document import odf_get_document 35 | from lpod.cleaner import clean_document 36 | 37 | 38 | if __name__ == '__main__': 39 | 40 | # Options initialisation 41 | usage = "%prog " 42 | description = "Clean malformed ODT documents" 43 | parser = OptionParser(usage, version=__version__, description=description) 44 | 45 | # Parse ! 46 | options, args = parser.parse_args() 47 | 48 | # Go ! 49 | if len(args) != 2: 50 | parser.print_help() 51 | exit(1) 52 | 53 | indoc = odf_get_document(args[0]) 54 | outdoc, error_nb = clean_document(indoc) 55 | if error_nb != 0: 56 | print '%d error(s) fixed.' % error_nb 57 | outdoc.save(target=args[1]) 58 | 59 | -------------------------------------------------------------------------------- /scripts/lpod-folder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: Jerome Dumonteil 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the standard library 29 | import os 30 | from optparse import OptionParser 31 | from sys import exit 32 | 33 | # Import from lpod 34 | from lpod import __version__ 35 | from lpod.document import odf_get_document 36 | 37 | 38 | if __name__ == '__main__': 39 | 40 | # Options initialisation 41 | usage = "%prog " 42 | description = "Convert standard ODF File to folder, and reverse." 43 | parser = OptionParser(usage, version=__version__, description=description) 44 | 45 | # Parse ! 46 | options, args = parser.parse_args() 47 | 48 | # Go ! 49 | if len(args) != 1: 50 | parser.print_help() 51 | exit(0) 52 | 53 | if os.path.isfile(args[0]): 54 | out_packaging = 'folder' 55 | elif os.path.isdir(args[0]): 56 | out_packaging = 'zip' 57 | else: 58 | raise ValueError, "no File or folder ?" 59 | doc = odf_get_document(args[0]) 60 | doc.save(packaging = out_packaging, pretty=True) 61 | -------------------------------------------------------------------------------- /test/samples/rst2odt_sample.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Wiki Syntax in 3 Minutes 3 | ======================== 4 | 5 | .. contents:: 6 | 7 | A title is made by underlining 8 | ============================== 9 | 10 | Use different underlines for subtitles 11 | -------------------------------------- 12 | 13 | To break paragraphs, just separate them with an empty line. 14 | 15 | Another paragraph. 16 | 17 | - a list using dash sign 18 | - a link to a website: http://hforge.org 19 | - a sublist: 20 | * a list using star sign 21 | * write in *italic*, in **bold** or in ``monotype`` 22 | 23 | .. figure:: image.png 24 | :width: 100 25 | 26 | Here is the caption of this image reduced to 100 pixels in width. 27 | You can click on http://www.itaapy.com/images/banner/;download to see it full 28 | size. 29 | 30 | You can include snippets without wiki [#]_ interpretation: 31 | 32 | :: 33 | 34 | class Module(Folder): 35 | 36 | def view(self): 37 | print u"Hello, world!" 38 | 39 | `This will not be interpreted`_ 40 | 41 | For a list of all possibilities like footnotes, tables, etc. `see the 42 | documentation`_. You can also use the toolbar. 43 | 44 | 45 | Tables 46 | ====== 47 | 48 | You can insert simple tables with this simple syntax: 49 | 50 | ======= ======= ====== 51 | Input 1 Input 2 Output 52 | ------- ------- ------ 53 | A B A or B 54 | ======= ======= ====== 55 | False False False 56 | True False True 57 | False True True 58 | True True True 59 | ======= ======= ====== 60 | 61 | 62 | Or a more complicated one like the following table: 63 | 64 | +------------+------------+-----------+ 65 | | Header 1 | Header 2 | Header 3 | 66 | +============+============+===========+ 67 | | body row 1 | column 2 | column 3 | 68 | +------------+------------+-----------+ 69 | | body row 2 | Cells may span columns.| 70 | +------------+------------+-----------+ 71 | | body row 3 | Cells may | - Cells | 72 | +------------+ span rows. | - contain | 73 | | body row 4 | | - blocks. | 74 | +------------+------------+-----------+ 75 | 76 | 77 | .. _`see the documentation`: 78 | http://docutils.sourceforge.net/docs/user/rst/quickref.html 79 | 80 | .. [#] see the wikipedia page: http://en.wikipedia.org/wiki/Wiki 81 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # Hervé Cauwelier 8 | # 9 | # This file is part of Lpod (see: http://lpod-project.net). 10 | # Lpod is free software; you can redistribute it and/or modify it under 11 | # the terms of either: 12 | # 13 | # a) the GNU General Public License as published by the Free Software 14 | # Foundation, either version 3 of the License, or (at your option) 15 | # any later version. 16 | # Lpod is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # You should have received a copy of the GNU General Public License 21 | # along with Lpod. If not, see . 22 | # 23 | # b) the Apache License, Version 2.0 (the "License"); 24 | # you may not use this file except in compliance with the License. 25 | # You may obtain a copy of the License at 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | 29 | from setuptools import setup 30 | import os 31 | from sys import executable 32 | import re 33 | 34 | # Import local 35 | from release import has_git, get_release 36 | 37 | g = {} 38 | execfile(os.path.join('lpod', '_version.py'), g) 39 | lpod_version = g['__version__'] 40 | 41 | #if has_git(): 42 | # release = '-'.join((lpod_version, get_release())) 43 | #else: 44 | release = lpod_version 45 | 46 | # Find all the scripts => It's easy: all the files in scripts/ 47 | scripts = [ os.path.join('scripts', filename) 48 | for filename in os.listdir('scripts') ] 49 | 50 | # Make the python_path.txt file 51 | open('python_path.txt', 'w').write(executable) 52 | 53 | setup(description='lpOD Library', 54 | license='GPLv3 + Apache v2', 55 | name='lpod-python', 56 | package_data={'': ['templates/*']}, 57 | package_dir={'lpod': 'lpod'}, 58 | scripts=scripts, 59 | packages=['lpod'], 60 | url='http://www.lpod-project.net/', 61 | version=release, 62 | author="lpOD Team", 63 | author_email="team@lpod-project.net") 64 | -------------------------------------------------------------------------------- /lpod/section.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from lpod 29 | from element import register_element_class, odf_element, odf_create_element 30 | 31 | 32 | 33 | def odf_create_section(style=None): 34 | """Create a section element of the given style. 35 | 36 | Arguments: 37 | 38 | style -- unicode 39 | 40 | Return: odf_element 41 | """ 42 | element = odf_create_element('text:section') 43 | if style: 44 | element.set_style(style) 45 | return element 46 | 47 | 48 | 49 | class odf_section(odf_element): 50 | """Specialised element for sections. 51 | """ 52 | 53 | def get_style(self): 54 | return self.get_attribute('text:style-name') 55 | 56 | 57 | def set_style(self, style): 58 | self.set_style_attribute('text:style-name', style) 59 | 60 | 61 | def get_formatted_text(self, context): 62 | result = [] 63 | for element in self.get_children(): 64 | result.append(element.get_formatted_text(context)) 65 | result.append(u'\n') 66 | return u''.join(result) 67 | 68 | 69 | 70 | register_element_class('text:section', odf_section) 71 | 72 | -------------------------------------------------------------------------------- /doc_make/index.rst: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2009-2013 Ars Aperta, Itaapy, Pierlis, Talend. 2 | 3 | Authors: David Versmisse 4 | Hervé Cauwelier 5 | Jean-Marie Gouarné 6 | Luis Belmar-Letelier 7 | Jerome Dumonteil 8 | 9 | This file is part of Lpod (see: http://lpod-project.net). 10 | Lpod is free software; you can redistribute it and/or modify it under 11 | the terms of either: 12 | 13 | a) the GNU General Public License as published by the Free Software 14 | Foundation, either version 3 of the License, or (at your option) 15 | any later version. 16 | Lpod is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | You should have received a copy of the GNU General Public License 21 | along with Lpod. If not, see . 22 | 23 | b) the Apache License, Version 2.0 (the "License"); 24 | you may not use this file except in compliance with the License. 25 | You may obtain a copy of the License at 26 | http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | Introduction 29 | ============== 30 | 31 | **lpOD** -- languages & platforms OpenDocument, 32 | is a Free Software project that offers, for high level use cases, an application programming interface dedicated to document processing with the `Python`, `Perl` and `Ruby` languages. It's complying with the `Open Document Format` (ODF), i.e. the 33 | `ISO/IEC 26300` international standard. 34 | 35 | lpOD is designed according to a **top-down** approach. The API is bound to the document 36 | functional structure and the user's point of view [1]_. As a consequence, it may be used without knowledge of the ODF specification, and 37 | allows the application developer to be focused on the business needs instead of the low level storage concerns. 38 | 39 | This documentation describes the lpod-python implementation. For more informations, see the global lpod-project documentation. 40 | 41 | 42 | 43 | .. [1] At the opposite of implementations based on a code generation from the ODF RelaxNG schema. 44 | 45 | 46 | 47 | Autogenerated code documentation 48 | ================================== 49 | 50 | .. toctree:: 51 | :maxdepth: 2 52 | 53 | autodocs.rst 54 | -------------------------------------------------------------------------------- /documentation/html/_sources/index.txt: -------------------------------------------------------------------------------- 1 | .. Copyright (c) 2009-2013 Ars Aperta, Itaapy, Pierlis, Talend. 2 | 3 | Authors: David Versmisse 4 | Hervé Cauwelier 5 | Jean-Marie Gouarné 6 | Luis Belmar-Letelier 7 | Jerome Dumonteil 8 | 9 | This file is part of Lpod (see: http://lpod-project.net). 10 | Lpod is free software; you can redistribute it and/or modify it under 11 | the terms of either: 12 | 13 | a) the GNU General Public License as published by the Free Software 14 | Foundation, either version 3 of the License, or (at your option) 15 | any later version. 16 | Lpod is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | You should have received a copy of the GNU General Public License 21 | along with Lpod. If not, see . 22 | 23 | b) the Apache License, Version 2.0 (the "License"); 24 | you may not use this file except in compliance with the License. 25 | You may obtain a copy of the License at 26 | http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | Introduction 29 | ============== 30 | 31 | **lpOD** -- languages & platforms OpenDocument, 32 | is a Free Software project that offers, for high level use cases, an application programming interface dedicated to document processing with the `Python`, `Perl` and `Ruby` languages. It's complying with the `Open Document Format` (ODF), i.e. the 33 | `ISO/IEC 26300` international standard. 34 | 35 | lpOD is designed according to a **top-down** approach. The API is bound to the document 36 | functional structure and the user's point of view [1]_. As a consequence, it may be used without knowledge of the ODF specification, and 37 | allows the application developer to be focused on the business needs instead of the low level storage concerns. 38 | 39 | This documentation describes the lpod-python implementation. For more informations, see the global lpod-project documentation. 40 | 41 | 42 | 43 | .. [1] At the opposite of implementations based on a code generation from the ODF RelaxNG schema. 44 | 45 | 46 | 47 | Autogenerated code documentation 48 | ================================== 49 | 50 | .. toctree:: 51 | :maxdepth: 2 52 | 53 | autodocs.rst 54 | -------------------------------------------------------------------------------- /test/test_content.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Romain Gauthier 6 | # Hervé Cauwelier 7 | # David Versmisse 8 | # 9 | # This file is part of Lpod (see: http://lpod-project.net). 10 | # Lpod is free software; you can redistribute it and/or modify it under 11 | # the terms of either: 12 | # 13 | # a) the GNU General Public License as published by the Free Software 14 | # Foundation, either version 3 of the License, or (at your option) 15 | # any later version. 16 | # Lpod is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # You should have received a copy of the GNU General Public License 21 | # along with Lpod. If not, see . 22 | # 23 | # b) the Apache License, Version 2.0 (the "License"); 24 | # you may not use this file except in compliance with the License. 25 | # You may obtain a copy of the License at 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | 29 | # Import from the Standard Library 30 | from unittest import TestCase, main 31 | 32 | # Import from lpod 33 | from lpod.const import ODF_CONTENT 34 | from lpod.content import odf_content 35 | from lpod.document import odf_get_document 36 | 37 | 38 | class ContentTestCase(TestCase): 39 | 40 | def setUp(self): 41 | self.document = document = odf_get_document('samples/base_text.odt') 42 | self.content = document.get_part(ODF_CONTENT) 43 | 44 | 45 | def test_get_content(self): 46 | self.assert_(type(self.content) is odf_content) 47 | 48 | 49 | def test_get_body(self): 50 | body = self.content.get_body() 51 | self.assertEqual(body.get_tag(), 'office:text') 52 | 53 | 54 | def test_get_styles(self): 55 | result = self.content.get_styles() 56 | self.assertEqual(len(result), 4) 57 | 58 | 59 | def test_get_styles_family(self): 60 | result = self.content.get_styles('font-face') 61 | self.assertEqual(len(result), 3) 62 | 63 | 64 | def test_get_style(self): 65 | style = self.content.get_style('section', u"Sect1") 66 | self.assertEqual(style.get_name(), u"Sect1") 67 | self.assertEqual(style.get_family(), 'section') 68 | 69 | 70 | 71 | if __name__ == '__main__': 72 | main() 73 | -------------------------------------------------------------------------------- /lpod/image.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from lpod 28 | from element import odf_create_element, odf_element, register_element_class 29 | 30 | 31 | def odf_create_image(url, type='simple', show='embed', actuate='onLoad'): 32 | """Create an image element showing the image at the given URL. 33 | 34 | Warning: image elements must be stored in a frame. 35 | 36 | Arguments: 37 | 38 | url -- str 39 | 40 | Return: odf_element 41 | """ 42 | image = odf_create_element('draw:image') 43 | image.set_url(url) 44 | image.set_type(type) 45 | image.set_show(show) 46 | image.set_actuate(actuate) 47 | return image 48 | 49 | 50 | 51 | class odf_image(odf_element): 52 | 53 | def get_url(self): 54 | return self.get_attribute('xlink:href') 55 | 56 | 57 | def set_url(self, url): 58 | return self.set_attribute('xlink:href', url) 59 | 60 | 61 | def get_type(self): 62 | return self.get_attribute('xlink:type') 63 | 64 | 65 | def set_type(self, type): 66 | return self.set_attribute('xlink:type', type) 67 | 68 | 69 | def get_show(self): 70 | return self.get_attribute('xlink:show') 71 | 72 | 73 | def set_show(self, show): 74 | return self.set_attribute('xlink:show', show) 75 | 76 | 77 | def get_actuate(self): 78 | return self.get_attribute('xlink:actuate') 79 | 80 | 81 | def set_actuate(self, actuate): 82 | return self.set_attribute('xlink:actuate', actuate) 83 | 84 | 85 | 86 | register_element_class('draw:image', odf_image) 87 | -------------------------------------------------------------------------------- /test/test_text.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.element import odf_text, odf_create_element 32 | 33 | 34 | class TextTestCase(TestCase): 35 | 36 | def setUp(self): 37 | element = odf_create_element('texttail') 38 | self.results = element.xpath('descendant::text()') 39 | 40 | 41 | def test_nodes(self): 42 | self.assertEqual(len(self.results), 2) 43 | 44 | 45 | def test_type(self): 46 | self.assert_(type(self.results[0]) is odf_text) 47 | 48 | 49 | def test_text(self): 50 | text = self.results[0] 51 | self.assertEqual(text, u"text") 52 | self.assert_(text.is_text() is True) 53 | self.assert_(text.is_tail() is False) 54 | 55 | 56 | def test_tail(self): 57 | tail = self.results[1] 58 | self.assertEqual(tail, u"tail") 59 | self.assert_(tail.is_text() is False) 60 | self.assert_(tail.is_tail() is True) 61 | 62 | 63 | 64 | class ParentTestCase(TestCase): 65 | 66 | def setUp(self): 67 | element = odf_create_element('texttail') 68 | self.results = element.xpath('descendant::text()') 69 | 70 | def test_text(self): 71 | text = self.results[0] 72 | self.assertEqual(text.get_parent().get_tag(), 'text:p') 73 | 74 | 75 | def test_tail(self): 76 | tail = self.results[1] 77 | self.assertEqual(tail.get_parent().get_tag(), 'text:span') 78 | 79 | 80 | 81 | if __name__ == '__main__': 82 | main() 83 | -------------------------------------------------------------------------------- /documentation/former_releases_notices/RELEASE-0.8: -------------------------------------------------------------------------------- 1 | LpOD 0.8 released 2 | =================== 3 | 4 | lpOD -- languages & platforms OpenDocument. 5 | Definition of a Free Software API implementing the ISO/IEC 26300 standard. 6 | Development, for higher level use cases, in Python, Perl and Ruby languages. 7 | of a top-down oriented API. 8 | 9 | - The architecture design is complete. 10 | - The functional lpOD coverage is 90% complete. 11 | - Only Python implementation is available (80% complete), and serves as the 12 | reference implementation 13 | - This release starts providing command-line tools for introspection and 14 | manipulation. 15 | - The documentation is now online http://docs.lpod-project.net 16 | - Cookbooks provide ready-to-use examples of the API for ODT, ODS and ODP 17 | (tables, tocs, notes, images frames, slides transitions, shapes, ... ) 18 | 19 | :Web: http://lpod-project.net 20 | :Documentation: http://docs.lpod-project.net 21 | :IRC: irc://irc.freenode.org/lpod 22 | 23 | 24 | Python Implementation 25 | ---------------------- 26 | 27 | Low-level API 28 | ~~~~~~~~~~~~~ 29 | 30 | - All types of styles are supported in the low-level API. 31 | - Text search and replace API is added 32 | - Basic shapes can be created: ellipse and circle, rectangle and square, and line. 33 | - Adding non ODF resources (e.g. images, pdf, ...) in documents 34 | - A Virtual File System (VFS) layer handles grabbing document from HTTP and FTP. 35 | - After starting with the libxml2 Python wrapper, switched to lxml for both speed and ease of use. 36 | 37 | High-level API 38 | ~~~~~~~~~~~~~~ 39 | 40 | - Template are provided, with empty body, i.e. the ODT template has no 41 | paragraph, the ODS template has no table and the ODP template has no draw 42 | page. 43 | - A document can grab styles from another document to merge them with its own 44 | ones. 45 | - A specific API is available on paragraphs to insert notes and annotation. 46 | - A specific API is available for tables to abstract the XML model, 47 | e.g. you can access cell "C3" without knowning the storage. 48 | - Tables can be created from and exported to CSV. 49 | - The full API to metadata is available. Only RDF would be missing. 50 | - The navigation API no longer use a context element. The element itself is 51 | the navigation API. 52 | 53 | Command-line Utilities 54 | ~~~~~~~~~~~~~~~~~~~~~~ 55 | 56 | - The lpod-show.py tool dumps a textual representation of the content. It can 57 | also dump the latter, style information and metadata list in a directory. 58 | - The lpod-meta.py introspection tool can list and edit metadata of the 59 | document. 60 | - The lpod-merge.py tool can merge documents of the same type. ODT, ODP, 61 | ODS and CSV and supported for now. 62 | - The lpod-highlight.py tool can apply a style on a text pattern. The default 63 | style is overlining as if you were using a yellow highlighter pen. 64 | 65 | 66 | -------------------------------------------------------------------------------- /documentation/former_releases_notices/RELEASE-0.9.2: -------------------------------------------------------------------------------- 1 | ========== 2 | LpOD 0.9.2 3 | ========== 4 | 5 | lpOD -- languages & platforms OpenDocument. 6 | Definition of a Free Software API implementing the ISO/IEC 26300 standard. 7 | Development, for higher level use cases, in Python, Perl and Ruby languages. 8 | of a top-down oriented API. 9 | 10 | This release adds preliminary support for the manifest, and scripts CLI is 11 | more homogeneous. A new script lpod-convert converts documents from one format 12 | to another (currently ods to odt, and reStructuredText to odt). The scripts 13 | lpod-rst2odt was dropped as it's now a duplicate of lpod-convert. 14 | 15 | - Web: http://lpod-project.net 16 | - Documentation: http://docs.lpod-project.net 17 | - IRC: irc://irc.freenode.org/lpod 18 | 19 | Low-level API 20 | ============= 21 | 22 | - The XML API in the odf_element class has seen many name shortenings: 23 | 24 | Before After 25 | -------------- ------- 26 | get_tagname get_tag 27 | set_tagname set_tag 28 | insert_element insert 29 | append_element append 30 | delete_element delete 31 | 32 | - "odf_element.delete" now accepts no argument to delete itself as a 33 | shortcut. 34 | 35 | - "odf_create_element" accepts qualified names such as "text:p" to quickly 36 | create a single element. 37 | 38 | - "get/set_boolean_attribute" as shortcuts to get/set a "true"/"false" 39 | attribute from a boolean ("true" and "false" accepted too). 40 | 41 | - The undocumented and unspecified VFS was dropped (and so the pygobject 42 | dependency). The Python Standard Library, third-party packages and library 43 | wrappers offer enough file and file-like objects with "read" and "write" 44 | methods for your needs. 45 | 46 | High-level API 47 | ============== 48 | 49 | - Methods "get_heading_*" now get an "outline_level" argument instead of 50 | "level" for consistency and not to mix with attribute "text:level" 51 | 52 | - Most scripts now write to the standard output, and provide "-o" option. 53 | Exceptions are lpod-highlight (in-place) and lpod-mm2odt (foo.mm -> 54 | foo.odt). 55 | 56 | - lpod-merge now merges documents in the first document provided, so this one 57 | provides the styles. 58 | 59 | - Methods "get__by_yyy" are merged in a single "get_" and 60 | several optional arguments. 61 | 62 | - Some variable methods were renamed for consistency: 63 | 64 | Before After 65 | ------------------- ------------------------ 66 | get_variable_list get_variable_decl_list 67 | get_variable_sets get_variable_set_list 68 | (missing) get_variable_set 69 | get_variable_value get_variable_set_value 70 | get_user_field_list get_user_field_decl_list 71 | 72 | - Method "get_tracked_changes" was moved from odf_content to odf_element, 73 | to group it with all other tracked changes methods. 74 | -------------------------------------------------------------------------------- /test/network_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | import os 29 | from cStringIO import StringIO 30 | from ftplib import FTP 31 | from unittest import TestCase, main 32 | from urllib import urlopen 33 | 34 | # Import from lpod 35 | from lpod.const import ODF_EXTENSIONS 36 | from lpod.container import odf_get_container 37 | 38 | 39 | # Tests requiring network moved from test_container and test_document 40 | class NetworkTest(TestCase): 41 | 42 | def test_http_container(self): 43 | file = urlopen('http://ftp.lpod-project.net/example.odt') 44 | container = odf_get_container(file) 45 | mimetype = container.get_part('mimetype') 46 | self.assertEqual(mimetype, ODF_EXTENSIONS['odt']) 47 | 48 | 49 | def test_ftp_container(self): 50 | ftp = FTP('ftp.lpod-project.net') 51 | ftp.login() 52 | file = StringIO() 53 | ftp.retrbinary('RETR example.odt', file.write) 54 | ftp.quit() 55 | file.seek(0) 56 | container = odf_get_container(file) 57 | mimetype = container.get_part('mimetype') 58 | self.assertEqual(mimetype, ODF_EXTENSIONS['odt']) 59 | 60 | 61 | def test_http_document(self): 62 | file = urlopen('http://ftp.lpod-project.net/example.odt') 63 | document = odf_get_document(file) 64 | self.assertEqual(document.get_mimetype(), ODF_EXTENSIONS['odt']) 65 | 66 | 67 | def test_ftp_document(self): 68 | ftp = FTP('ftp.lpod-project.net') 69 | ftp.login() 70 | file = StringIO() 71 | ftp.retrbinary('RETR example.odt', file.write) 72 | ftp.quit() 73 | file.seek(0) 74 | document = odf_get_document(file) 75 | self.assertEqual(document.get_mimetype(), ODF_EXTENSIONS['odt']) 76 | 77 | 78 | 79 | 80 | if __name__ == '__main__': 81 | main() 82 | -------------------------------------------------------------------------------- /release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from subprocess import Popen, PIPE 30 | from sys import argv 31 | from os.path import basename, exists 32 | 33 | # Import from lpod 34 | from scriptutils import printerr 35 | 36 | 37 | try: 38 | # builtin on Windows 39 | WindowsError 40 | except NameError: 41 | class WindowsError(OSError): 42 | pass 43 | 44 | 45 | def _run_command(command): 46 | popen = Popen(command, stdout=PIPE, stderr=PIPE) 47 | stdoutdata, stderrdata = popen.communicate() 48 | if popen.returncode != 0 or stderrdata: 49 | raise ValueError 50 | return stdoutdata 51 | 52 | 53 | 54 | def has_git(): 55 | if not exists('.git'): 56 | return False 57 | try: 58 | _run_command(['git', 'branch']) 59 | except (ValueError, OSError, WindowsError): 60 | return False 61 | return True 62 | 63 | 64 | 65 | def get_release(): 66 | # XXX do it in one git command 67 | output = _run_command(['git', 'branch']) 68 | for line in output.splitlines(): 69 | if line.startswith('*'): 70 | branch = line[2:] 71 | break 72 | output = _run_command(['git', 'describe', '--tags', '--always']).strip() 73 | if not '-' in output: 74 | return output 75 | version, delta, sha = output.split('-') 76 | if branch == 'master': 77 | #return '-'.join((version, delta, sha)) 78 | return sha 79 | #return '-'.join((branch, version, delta, sha)) 80 | return '-'.join((branch, sha)) 81 | 82 | 83 | 84 | def get_git_files(): 85 | files = _run_command(['git', 'ls-files']) 86 | return [ name.strip() for name in files.splitlines() ] 87 | 88 | 89 | 90 | if __name__ == '__main__': 91 | try: 92 | print get_release() 93 | except: 94 | printerr('%s: unable to read info' % basename(argv[0])) 95 | -------------------------------------------------------------------------------- /lpod/cleaner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from lpod 29 | from lpod.element import PREV_SIBLING 30 | 31 | 32 | 33 | def _test_text_h(document): 34 | body = document.get_body() 35 | 36 | for heading in body.get_headings(): 37 | parent = heading.get_parent() 38 | # Ok ? 39 | if parent.get_tag() != 'office:text': 40 | return 'nested "text:h" detected' 41 | 42 | return True 43 | 44 | 45 | def _fix_text_h(document): 46 | body = document.get_body() 47 | error_nb = 0 48 | 49 | error_detected = True 50 | while error_detected: 51 | error_detected = False 52 | for heading in body.get_headings(): 53 | parent = heading.get_parent() 54 | # Ok ? 55 | if parent.get_tag() == 'office:text': 56 | continue 57 | 58 | # Else, ... 59 | error_detected = True 60 | error_nb += 1 61 | 62 | # XXX The texts are not children ?? 63 | # We move all elements outside this "bad" container 64 | for element in parent.get_children(): 65 | parent.insert(element, xmlposition=PREV_SIBLING) 66 | # And we remove it 67 | parent.delete() 68 | 69 | return error_nb 70 | 71 | 72 | 73 | def test_document(document): 74 | """Test if the document is valid. 75 | 76 | Returns: True if the document is valid 77 | or a otherwise. This str describes the problem. 78 | """ 79 | 80 | # Test, ... 81 | return _test_text_h(document) 82 | 83 | 84 | 85 | def clean_document(document): 86 | """This method returns a cloned, cleaned document and the number of fixed 87 | errors""" 88 | outdoc = document.clone() 89 | 90 | # Fix, ... 91 | error_nb = _fix_text_h(outdoc) 92 | 93 | return outdoc, error_nb 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /documentation/former_releases_notices/RELEASE-0.9.0: -------------------------------------------------------------------------------- 1 | ====================== 2 | LpOD 0.9.0 aka Orvieto 3 | ====================== 4 | 5 | lpOD -- languages & platforms OpenDocument. 6 | Definition of a Free Software API implementing the ISO/IEC 26300 standard. 7 | Development, for higher level use cases, in Python, Perl and Ruby languages. 8 | of a top-down oriented API. 9 | 10 | This release focuses on style and table support, and polishing the existing 11 | API. Command-line tools were greatly improved and enriched. 12 | 13 | - Web: http://lpod-project.net 14 | - Documentation: http://docs.lpod-project.net 15 | - IRC: irc://irc.freenode.org/lpod 16 | 17 | Low-level API 18 | ============= 19 | 20 | - Default numeric types were added, targeting the French locale for now. 21 | 22 | - The text API is now richer. 23 | 24 | High-level API 25 | ============== 26 | 27 | - Started to implement a templating language in the content of ODF documents. 28 | Only setting values and "if" are implemented for now, and only on text. 29 | 30 | You can see an example template in "python/templates/test_template.ott" and an 31 | example script in "python/templates/test_template.py". 32 | 33 | Templating the metadata is left as an exercise to the interested reader. 34 | 35 | - Tables of content can now be filled with the titles found in the document. 36 | 37 | - Draw page can use transitions (fade by default). 38 | 39 | - Tables are quite faster and easier to use since you can access any 40 | row/column/cell without having to expand the table first. 41 | 42 | - Most high-level elements support outputting reStructuredText representation. 43 | 44 | - Medium-complexity reStructuredText documents can be converted to ODT, from 45 | scratch or appended to an existing document (docutils required). 46 | 47 | Command-line Utilities 48 | ====================== 49 | 50 | - The lpod-show.py tool dumps a textual representation of the content (informal 51 | or reStructuredText). It can also dump the latter, images, style information 52 | and metadata list in a directory. 53 | 54 | - The lpod-style.py introspection tool shows the list of styles of the 55 | document, whether it is used, and is able to remove them all. It can also 56 | merge styles from one document to another. 57 | 58 | - The lpod-meta.py introspection tool can list and edit metadata of the 59 | document. 60 | 61 | - The lpod-merge.py tool can merge documents of the same type. ODT, ODS and 62 | CSV and supported for now. ODP to come. 63 | 64 | - The lpod-highlight.py tool can apply a style on a text pattern. The default 65 | style is overlining as if you were using a yellow highlighter pen. 66 | 67 | - The lpod-mm2odt.py tool converts XML mind-map files to ODT. 68 | 69 | - The lpod-rst2odt.py tool converts reStructuredText document to ODT. 70 | 71 | Documentation 72 | ============= 73 | 74 | - 80 % of the documentation is implemented. There is still much work on the 75 | styles part. 76 | 77 | 78 | Packaging 79 | ========= 80 | 81 | - PKGBUILD and ebuild packages contributed. Deb and RPM to come. 82 | -------------------------------------------------------------------------------- /test/test_toc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.document import odf_get_document 32 | from lpod.toc import odf_create_toc 33 | 34 | 35 | def get_toc_lines(toc): 36 | return [paragraph.get_text() 37 | for paragraph in toc.get_paragraphs()] 38 | 39 | 40 | 41 | class TOCTest(TestCase): 42 | 43 | def setUp(self): 44 | self.document = odf_get_document("samples/toc.odt") 45 | self.expected = [ 46 | u"Table des matières", 47 | u"1. Level 1 title 1", 48 | u"1.1. Level 2 title 1", 49 | u"2. Level 1 title 2", 50 | u"2.1.1. Level 3 title 1", 51 | u"2.2. Level 2 title 2", 52 | u"3. Level 1 title 3", 53 | u"3.1. Level 2 title 1", 54 | u"3.1.1. Level 3 title 1", 55 | u"3.1.2. Level 3 title 2", 56 | u"3.2. Level 2 title 2", 57 | u"3.2.1. Level 3 title 1", 58 | u"3.2.2. Level 3 title 2"] 59 | 60 | 61 | def test_toc_fill_unattached(self): 62 | toc = odf_create_toc(u"Table des matières") 63 | self.assertRaises(ValueError, toc.fill) 64 | 65 | 66 | def test_toc_fill_unattached_document(self): 67 | toc = odf_create_toc(u"Table des matières") 68 | toc.fill(self.document) 69 | toc_lines = get_toc_lines(toc) 70 | self.assertEqual(toc_lines, self.expected) 71 | 72 | 73 | def test_toc_fill_attached(self): 74 | document = self.document.clone() 75 | toc = odf_create_toc(u"Table des matières") 76 | document.get_body().append(toc) 77 | toc.fill() 78 | toc_lines = get_toc_lines(toc) 79 | self.assertEqual(toc_lines, self.expected) 80 | 81 | 82 | 83 | if __name__ == '__main__': 84 | main() 85 | 86 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Romain Gauthier 6 | # Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from unittest import TestLoader, TestSuite, TextTestRunner 30 | 31 | # Import tests 32 | import test_bookmark 33 | import test_container 34 | import test_content 35 | import test_datatype 36 | import test_document 37 | import test_draw_page 38 | import test_element 39 | import test_frame 40 | import test_heading 41 | import test_image 42 | import test_link 43 | import test_list 44 | import test_meta 45 | import test_note 46 | import test_paragraph 47 | import test_reference 48 | import test_section 49 | import test_shapes 50 | import test_span 51 | import test_style 52 | import test_styles 53 | import test_table 54 | import test_text 55 | import test_tracked_changes 56 | import test_utils 57 | import test_variable 58 | import test_xmlpart 59 | 60 | 61 | test_modules = [test_bookmark, 62 | test_container, 63 | test_content, 64 | test_datatype, 65 | test_document, 66 | test_draw_page, 67 | test_element, 68 | test_frame, 69 | test_heading, 70 | test_image, 71 | test_link, 72 | test_list, 73 | test_meta, 74 | test_note, 75 | test_paragraph, 76 | test_reference, 77 | test_section, 78 | test_shapes, 79 | test_span, 80 | test_style, 81 | test_styles, 82 | test_table, 83 | test_text, 84 | test_tracked_changes, 85 | test_utils, 86 | test_variable, 87 | test_xmlpart] 88 | 89 | 90 | loader = TestLoader() 91 | 92 | if __name__ == '__main__': 93 | suite = TestSuite() 94 | for module in test_modules: 95 | suite.addTest(loader.loadTestsFromModule(module)) 96 | 97 | TextTestRunner(verbosity=1).run(suite) 98 | -------------------------------------------------------------------------------- /scripts/lpod-diff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the standard library 29 | from difflib import unified_diff, ndiff 30 | from optparse import OptionParser 31 | from sys import exit, stdout 32 | from time import ctime 33 | from os import stat 34 | 35 | # Import from lpod 36 | from lpod import __version__ 37 | from lpod.document import odf_get_document 38 | 39 | 40 | 41 | if __name__ == '__main__': 42 | 43 | # Options initialisation 44 | usage = "%prog " 45 | description = "Show a diff between doc1.odt and doc2.odt" 46 | parser = OptionParser(usage, version=__version__, description=description) 47 | 48 | # --ndiff 49 | parser.add_option('-n', '--ndiff', action='store_true', default=False, 50 | help='use a contextual "ndiff" format to show the output') 51 | 52 | # Parse ! 53 | options, args = parser.parse_args() 54 | 55 | # Go ! 56 | if len(args) != 2: 57 | parser.print_help() 58 | exit(1) 59 | 60 | # Open the 2 documents, diff only for ODT 61 | doc1 = odf_get_document(args[0]) 62 | doc2 = odf_get_document(args[1]) 63 | if doc1.get_type() != 'text' or doc2.get_type() != 'text': 64 | parser.print_help() 65 | exit(1) 66 | 67 | # Convert in text before the diff 68 | text1 = doc1.get_formatted_text(True).splitlines(True) 69 | text2 = doc2.get_formatted_text(True).splitlines(True) 70 | 71 | # Make the diff ! 72 | if options.ndiff: 73 | result = ndiff(text1, text2, None, None) 74 | result = [ line for line in result if not line.startswith(u' ') ] 75 | else: 76 | fromdate = ctime(stat(args[0]).st_mtime) 77 | todate = ctime(stat(args[1]).st_mtime) 78 | result = unified_diff(text1, text2, args[0], args[1], fromdate, todate) 79 | result = u''.join(result) 80 | encoding = stdout.encoding if stdout.encoding is not None else 'utf-8' 81 | result = result.encode(encoding) 82 | 83 | # And print it ! 84 | print result 85 | -------------------------------------------------------------------------------- /test/test_span.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.document import odf_get_document 32 | from lpod.span import odf_create_span 33 | 34 | 35 | class TestSpan(TestCase): 36 | 37 | def setUp(self): 38 | self.document = document = odf_get_document('samples/span_style.odt') 39 | self.body = document.get_body() 40 | 41 | 42 | def test_create_span(self): 43 | span = odf_create_span(u'my text', style='my_style') 44 | expected = ('' 45 | 'my text' 46 | '') 47 | self.assertEqual(span.serialize(), expected) 48 | 49 | 50 | def test_get_span_list(self): 51 | body = self.body 52 | result = body.get_spans() 53 | self.assertEqual(len(result), 2) 54 | element = result[0] 55 | expected = ('' 56 | 'moustache' 57 | '') 58 | self.assertEqual(element.serialize(), expected) 59 | 60 | 61 | def test_get_span_list_style(self): 62 | body = self.body 63 | result = body.get_spans(style='T2') 64 | self.assertEqual(len(result), 1) 65 | element = result[0] 66 | expected = ('' 67 | 'rouge' 68 | '') 69 | self.assertEqual(element.serialize(), expected) 70 | 71 | 72 | def test_get_span(self): 73 | body = self.body 74 | span = body.get_span(position=1) 75 | expected = ('' 76 | 'rouge' 77 | '') 78 | self.assertEqual(span.serialize(), expected) 79 | 80 | 81 | def test_insert_span(self): 82 | body = self.body.clone() 83 | span = odf_create_span('my_style', u'my text') 84 | paragraph = body.get_paragraph(position=0) 85 | paragraph.append(span) 86 | 87 | 88 | 89 | if __name__ == '__main__': 90 | main() 91 | -------------------------------------------------------------------------------- /test/test_section.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.document import odf_get_document 32 | from lpod.section import odf_create_section 33 | 34 | 35 | class TestSection(TestCase): 36 | 37 | def setUp(self): 38 | self.document = document = odf_get_document('samples/base_text.odt') 39 | self.body = document.get_body() 40 | 41 | 42 | def test_create_simple_section(self): 43 | """The idea is to test only with the mandatory arguments (none 44 | in this case), not to test odf_create_element which is done in 45 | test_xmlpart. 46 | """ 47 | element = odf_create_section() 48 | excepted = '' 49 | self.assertEqual(element.serialize(), excepted) 50 | 51 | 52 | def test_create_complex_section(self): 53 | """The idea is to test with all possible arguments. If some arguments 54 | are contradictory or trigger different behaviours, test all those 55 | combinations separately. 56 | """ 57 | element = odf_create_section(style='Standard') 58 | excepted = '' 59 | self.assertEqual(element.serialize(), excepted) 60 | 61 | 62 | def test_get_section_list(self): 63 | body = self.body 64 | sections = body.get_sections() 65 | self.assertEqual(len(sections), 2) 66 | second = sections[1] 67 | name = second.get_attribute('text:name') 68 | self.assertEqual(name, "Section2") 69 | 70 | 71 | def test_get_section_list_style(self): 72 | body = self.body 73 | sections = body.get_sections(style='Sect1') 74 | self.assertEqual(len(sections), 2) 75 | section = sections[0] 76 | name = section.get_attribute('text:name') 77 | self.assertEqual(name, "Section1") 78 | 79 | 80 | def test_get_section(self): 81 | body = self.body 82 | section = body.get_section(position=1) 83 | name = section.get_attribute('text:name') 84 | self.assertEqual(name, "Section2") 85 | 86 | 87 | 88 | if __name__ == '__main__': 89 | main() 90 | -------------------------------------------------------------------------------- /doc_make/static_in/lpod.css: -------------------------------------------------------------------------------- 1 | @import url("default.css"); 2 | 3 | @font-face { 4 | font-family: goodstyle; 5 | font-style: normal; 6 | font-weight: normal; 7 | src: url(LinLibertine_R.woff); 8 | } 9 | 10 | body { 11 | background-color: white; 12 | color: black; 13 | margin-left: 28px; 14 | font-family: goodstyle, Arial, Helvetica, sans-serif; 15 | font-size: 13pt; 16 | line-height: 100%; 17 | } 18 | 19 | ul { 20 | margin: 0 0 0 0; 21 | } 22 | 23 | div.related { 24 | background-color: #444; 25 | } 26 | 27 | a, 28 | div.sphinxsidebar h3 a, 29 | div.sphinxsidebar a, 30 | div.footer a { 31 | color: #444; 32 | } 33 | 34 | div.sphinxsidebar h3, 35 | div.sphinxsidebar h4 { 36 | font-family: goodstyle, Arial, Helvetica, sans-serif; 37 | font-size: 1.2em; 38 | color: #000; 39 | } 40 | 41 | div.sphinxsidebar ul { 42 | color: #000; 43 | } 44 | 45 | div.sphinxsidebar input { 46 | font-family: goodstyle, Arial, Helvetica, sans-serif; 47 | border-color: #444; 48 | } 49 | 50 | div.document { 51 | background-color: #f5f8e4; 52 | } 53 | 54 | div.body h1, 55 | div.body h2, 56 | div.body h3, 57 | div.body h4, 58 | div.body h5, 59 | div.body h6 { 60 | color: #000; 61 | font-family: goodstyle, Arial, Helvetica, sans-serif; 62 | border-color: #444; 63 | background-color: transparent; 64 | border-bottom: 1px solid #444; 65 | } 66 | 67 | div.body h1 { margin-top: 0; font-size: 160%; } 68 | div.body h2 { font-size: 140%; } 69 | div.body h3 { font-size: 120%; } 70 | div.body h4 { font-size: 110%; } 71 | div.body h5 { font-size: 105%; } 72 | div.body h6 { font-size: 100%; } 73 | 74 | div.footer { 75 | color: #000; 76 | } 77 | 78 | li.toctree-l2 { 79 | font-size: 90%; 80 | } 81 | 82 | li.toctree-l3 { 83 | font-size: 80%; 84 | } 85 | 86 | div.sphinxsidebarwrapper ul { 87 | list-style-type: disc; 88 | margin-top: 1px; 89 | padding-left: 6px; 90 | } 91 | 92 | div.sphinxsidebarwrapper h3 { 93 | font-size: 90%; 94 | font-weight: bold; 95 | } 96 | 97 | div.body h1 { 98 | font-size: 110%; 99 | } 100 | div.body h2 { 101 | font-size: 105%; 102 | } 103 | div.body h3, div.body h4 { 104 | font-size: 100%; 105 | } 106 | 107 | div.body p.topic-title { 108 | margin-bottom: 2px; 109 | font-size: 100%; 110 | } 111 | 112 | div.body p, div.body dd, div.body li { 113 | text-align: justify; 114 | line-height: 100%; 115 | } 116 | 117 | div.sphinxsidebar p { 118 | color: #444; 119 | } 120 | 121 | tt.descname { 122 | background-color: transparent; 123 | font-weight: bold; 124 | font-size: 1.1em; 125 | } 126 | tt.descclassname { 127 | background-color: transparent; 128 | font-weight: bold; 129 | font-size: 1.1em; 130 | } 131 | 132 | dl { 133 | padding-top: 10px; 134 | } 135 | 136 | table.indextable dt { 137 | font-family: monospace; 138 | margin-top: 0; 139 | margin-bottom: 0; 140 | font-size: 0.80em; 141 | padding-bottom: 3px; 142 | } 143 | 144 | div.section { 145 | padding-top: 20px; 146 | padding-bottom: 30px; 147 | } 148 | 149 | div.highlight-python { 150 | font-size: .8em; 151 | } 152 | 153 | #introduction p > em { 154 | text-align: right; 155 | float: right; 156 | } 157 | 158 | #introduction p { 159 | font-size: 90%; 160 | margin-bottom: 3px; 161 | } 162 | 163 | #introduction #id2.docutils.footnote { 164 | font-size: 80%; 165 | margin-top: 25px; 166 | } 167 | 168 | #introduction table.docutils.footnote { 169 | font-size: 80%; 170 | margin-top: 5px; 171 | } 172 | -------------------------------------------------------------------------------- /documentation/html/_static/lpod.css: -------------------------------------------------------------------------------- 1 | @import url("default.css"); 2 | 3 | @font-face { 4 | font-family: goodstyle; 5 | font-style: normal; 6 | font-weight: normal; 7 | src: url(LinLibertine_R.woff); 8 | } 9 | 10 | body { 11 | background-color: white; 12 | color: black; 13 | margin-left: 28px; 14 | font-family: goodstyle, Arial, Helvetica, sans-serif; 15 | font-size: 13pt; 16 | line-height: 100%; 17 | } 18 | 19 | ul { 20 | margin: 0 0 0 0; 21 | } 22 | 23 | div.related { 24 | background-color: #444; 25 | } 26 | 27 | a, 28 | div.sphinxsidebar h3 a, 29 | div.sphinxsidebar a, 30 | div.footer a { 31 | color: #444; 32 | } 33 | 34 | div.sphinxsidebar h3, 35 | div.sphinxsidebar h4 { 36 | font-family: goodstyle, Arial, Helvetica, sans-serif; 37 | font-size: 1.2em; 38 | color: #000; 39 | } 40 | 41 | div.sphinxsidebar ul { 42 | color: #000; 43 | } 44 | 45 | div.sphinxsidebar input { 46 | font-family: goodstyle, Arial, Helvetica, sans-serif; 47 | border-color: #444; 48 | } 49 | 50 | div.document { 51 | background-color: #f5f8e4; 52 | } 53 | 54 | div.body h1, 55 | div.body h2, 56 | div.body h3, 57 | div.body h4, 58 | div.body h5, 59 | div.body h6 { 60 | color: #000; 61 | font-family: goodstyle, Arial, Helvetica, sans-serif; 62 | border-color: #444; 63 | background-color: transparent; 64 | border-bottom: 1px solid #444; 65 | } 66 | 67 | div.body h1 { margin-top: 0; font-size: 160%; } 68 | div.body h2 { font-size: 140%; } 69 | div.body h3 { font-size: 120%; } 70 | div.body h4 { font-size: 110%; } 71 | div.body h5 { font-size: 105%; } 72 | div.body h6 { font-size: 100%; } 73 | 74 | div.footer { 75 | color: #000; 76 | } 77 | 78 | li.toctree-l2 { 79 | font-size: 90%; 80 | } 81 | 82 | li.toctree-l3 { 83 | font-size: 80%; 84 | } 85 | 86 | div.sphinxsidebarwrapper ul { 87 | list-style-type: disc; 88 | margin-top: 1px; 89 | padding-left: 6px; 90 | } 91 | 92 | div.sphinxsidebarwrapper h3 { 93 | font-size: 90%; 94 | font-weight: bold; 95 | } 96 | 97 | div.body h1 { 98 | font-size: 110%; 99 | } 100 | div.body h2 { 101 | font-size: 105%; 102 | } 103 | div.body h3, div.body h4 { 104 | font-size: 100%; 105 | } 106 | 107 | div.body p.topic-title { 108 | margin-bottom: 2px; 109 | font-size: 100%; 110 | } 111 | 112 | div.body p, div.body dd, div.body li { 113 | text-align: justify; 114 | line-height: 100%; 115 | } 116 | 117 | div.sphinxsidebar p { 118 | color: #444; 119 | } 120 | 121 | tt.descname { 122 | background-color: transparent; 123 | font-weight: bold; 124 | font-size: 1.1em; 125 | } 126 | tt.descclassname { 127 | background-color: transparent; 128 | font-weight: bold; 129 | font-size: 1.1em; 130 | } 131 | 132 | dl { 133 | padding-top: 10px; 134 | } 135 | 136 | table.indextable dt { 137 | font-family: monospace; 138 | margin-top: 0; 139 | margin-bottom: 0; 140 | font-size: 0.80em; 141 | padding-bottom: 3px; 142 | } 143 | 144 | div.section { 145 | padding-top: 20px; 146 | padding-bottom: 30px; 147 | } 148 | 149 | div.highlight-python { 150 | font-size: .8em; 151 | } 152 | 153 | #introduction p > em { 154 | text-align: right; 155 | float: right; 156 | } 157 | 158 | #introduction p { 159 | font-size: 90%; 160 | margin-bottom: 3px; 161 | } 162 | 163 | #introduction #id2.docutils.footnote { 164 | font-size: 80%; 165 | margin-top: 25px; 166 | } 167 | 168 | #introduction table.docutils.footnote { 169 | font-size: 80%; 170 | margin-top: 5px; 171 | } 172 | -------------------------------------------------------------------------------- /scriptutils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from mimetypes import guess_type 29 | from os.path import exists, isfile 30 | from StringIO import StringIO 31 | from sys import stdin, stdout, stderr 32 | 33 | # Import from lpod 34 | 35 | 36 | """Utilities shared by the scripts. 37 | """ 38 | 39 | 40 | def check_target_file(path, kind="file"): 41 | if exists(path): 42 | message = 'The %s "%s" exists, overwrite it? [y/N]' 43 | stderr.write(message % (kind, path)) 44 | stderr.flush() 45 | line = stdin.readline() 46 | line = line.strip().lower() 47 | if line != 'y': 48 | stderr.write('Operation aborted\n') 49 | stderr.flush() 50 | exit(0) 51 | 52 | 53 | 54 | def check_target_directory(path): 55 | return check_target_file(path, kind="directory") 56 | 57 | 58 | 59 | encoding_map = {'gzip': 'application/x-gzip', 'bzip2': 'application/x-bzip2'} 60 | 61 | 62 | def get_mimetype(filename): 63 | if not isfile(filename): 64 | return 'application/x-directory' 65 | mimetype, encoding = guess_type(filename) 66 | if encoding is not None: 67 | return encoding_map.get(encoding, encoding) 68 | if mimetype is not None: 69 | return mimetype 70 | return 'application/octet-stream' 71 | 72 | 73 | 74 | def add_option_output(parser, metavar="FILE", complement=""): 75 | help = "dump the output into %s %s" % (metavar, complement) 76 | parser.add_option("-o", "--output", metavar=metavar, help=help) 77 | 78 | 79 | 80 | def printinfo(*args, **kw): 81 | # TODO switch to print function 82 | indent = kw.get('indent', 0) 83 | if indent: 84 | stderr.write(' ' * indent) 85 | encoding = stderr.encoding if stderr.encoding is not None else 'utf-8' 86 | output = ' '.join(arg.encode(encoding) for arg in args) 87 | stderr.write(output) 88 | stderr.write("\n") 89 | 90 | 91 | def printwarn(*args, **kw): 92 | printinfo("Warning:", *args, **kw) 93 | 94 | 95 | def printerr(*args, **kw): 96 | printinfo("Error:", *args, **kw) 97 | 98 | 99 | 100 | class StdoutWriter(StringIO): 101 | """Some proxy to write output to stdout in scripts. Because The zipfile 102 | module raises "IOError: [Errno 29] Illegal seek" when writing to stdout 103 | directly. 104 | """ 105 | 106 | def write(self, s): 107 | stdout.write(s) 108 | StringIO.write(self, s) 109 | -------------------------------------------------------------------------------- /lpod/scriptutils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from mimetypes import guess_type 29 | from os.path import exists, isfile 30 | from StringIO import StringIO 31 | from sys import stdin, stdout, stderr 32 | 33 | # Import from lpod 34 | 35 | 36 | """Utilities shared by the scripts. 37 | """ 38 | 39 | 40 | def check_target_file(path, kind="file"): 41 | if exists(path): 42 | message = 'The %s "%s" exists, overwrite it? [y/N]' 43 | stderr.write(message % (kind, path)) 44 | stderr.flush() 45 | line = stdin.readline() 46 | line = line.strip().lower() 47 | if line != 'y': 48 | stderr.write('Operation aborted\n') 49 | stderr.flush() 50 | exit(0) 51 | 52 | 53 | 54 | def check_target_directory(path): 55 | return check_target_file(path, kind="directory") 56 | 57 | 58 | 59 | encoding_map = {'gzip': 'application/x-gzip', 'bzip2': 'application/x-bzip2'} 60 | 61 | 62 | def get_mimetype(filename): 63 | if not isfile(filename): 64 | return 'application/x-directory' 65 | mimetype, encoding = guess_type(filename) 66 | if encoding is not None: 67 | return encoding_map.get(encoding, encoding) 68 | if mimetype is not None: 69 | return mimetype 70 | return 'application/octet-stream' 71 | 72 | 73 | 74 | def add_option_output(parser, metavar="FILE", complement=""): 75 | help = "dump the output into %s %s" % (metavar, complement) 76 | parser.add_option("-o", "--output", metavar=metavar, help=help) 77 | 78 | 79 | 80 | def printinfo(*args, **kw): 81 | # TODO switch to print function 82 | indent = kw.get('indent', 0) 83 | if indent: 84 | stderr.write(' ' * indent) 85 | encoding = stderr.encoding if stderr.encoding is not None else 'utf-8' 86 | output = ' '.join(arg.encode(encoding) for arg in args) 87 | stderr.write(output) 88 | stderr.write("\n") 89 | 90 | 91 | def printwarn(*args, **kw): 92 | printinfo("Warning:", *args, **kw) 93 | 94 | 95 | def printerr(*args, **kw): 96 | printinfo("Error:", *args, **kw) 97 | 98 | 99 | 100 | class StdoutWriter(StringIO): 101 | """Some proxy to write output to stdout in scripts. Because The zipfile 102 | module raises "IOError: [Errno 29] Illegal seek" when writing to stdout 103 | directly. 104 | """ 105 | 106 | def write(self, s): 107 | stdout.write(s) 108 | StringIO.write(self, s) 109 | -------------------------------------------------------------------------------- /test/test_image.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Romain Gauthier 6 | # Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from unittest import TestCase, main 30 | 31 | # Import from lpod 32 | from lpod.document import odf_get_document 33 | from lpod.element import NEXT_SIBLING 34 | from lpod.frame import odf_create_frame 35 | from lpod.image import odf_create_image 36 | 37 | 38 | class TestImage(TestCase): 39 | 40 | def setUp(self): 41 | self.document = document = odf_get_document('samples/frame_image.odp') 42 | self.body = document.get_body() 43 | self.path = 'Pictures/10000000000001D40000003C8B3889D9.png' 44 | 45 | 46 | def test_create_image(self): 47 | image = odf_create_image(self.path) 48 | expected = ('' % self.path) 50 | self.assertEqual(image.serialize(), expected) 51 | 52 | 53 | def test_get_image_list(self): 54 | body = self.body 55 | result = body.get_images() 56 | self.assertEqual(len(result), 1) 57 | element = result[0] 58 | self.assertEqual(element.get_attribute('xlink:href'), self.path) 59 | 60 | 61 | def test_get_image_by_name(self): 62 | body = self.body 63 | element = body.get_image(name=u"Logo") 64 | # Searched by frame but got the inner image with no name 65 | self.assertEqual(element.get_attribute('xlink:href'), self.path) 66 | 67 | 68 | def test_get_image_by_position(self): 69 | body = self.body 70 | element = body.get_image(position=0) 71 | self.assertEqual(element.get_attribute('xlink:href'), self.path) 72 | 73 | 74 | def test_get_image_by_path(self): 75 | body = self.body 76 | element = body.get_image(url='.png') 77 | self.assertEqual(element.get_attribute('xlink:href'), self.path) 78 | 79 | 80 | def test_insert_image(self): 81 | body = self.body.clone() 82 | path = 'a/path' 83 | image = odf_create_image(path) 84 | frame = odf_create_frame(u"Image Frame", size=('0cm', '0cm'), 85 | style='Graphics') 86 | frame.append(image) 87 | body.get_frame().insert(frame, NEXT_SIBLING) 88 | element = body.get_image(name=u"Image Frame") 89 | self.assertEqual(element.get_attribute('xlink:href'), path) 90 | element = body.get_image(position=1) 91 | self.assertEqual(element.get_attribute('xlink:href'), path) 92 | 93 | 94 | 95 | if __name__ == '__main__': 96 | main() 97 | -------------------------------------------------------------------------------- /lpod/content.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # Hervé Cauwelier 7 | # Romain Gauthier 8 | # 9 | # This file is part of Lpod (see: http://lpod-project.net). 10 | # Lpod is free software; you can redistribute it and/or modify it under 11 | # the terms of either: 12 | # 13 | # a) the GNU General Public License as published by the Free Software 14 | # Foundation, either version 3 of the License, or (at your option) 15 | # any later version. 16 | # Lpod is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # You should have received a copy of the GNU General Public License 21 | # along with Lpod. If not, see . 22 | # 23 | # b) the Apache License, Version 2.0 (the "License"); 24 | # you may not use this file except in compliance with the License. 25 | # You may obtain a copy of the License at 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | 29 | # Import from lpod 30 | #from utils import obsolete 31 | from xmlpart import odf_xmlpart 32 | 33 | 34 | class odf_content(odf_xmlpart): 35 | 36 | def get_body(self): 37 | return self.get_root().get_document_body() 38 | 39 | 40 | # The following two seem useless but they match styles API 41 | 42 | def _get_style_contexts(self, family): 43 | if family == 'font-face': 44 | return (self.get_element('//office:font-face-decls'),) 45 | return (self.get_element('//office:font-face-decls'), 46 | self.get_element('//office:automatic-styles')) 47 | 48 | 49 | # 50 | # Public API 51 | # 52 | 53 | def get_styles(self, family=None): 54 | """Return the list of styles in the Content part, optionally limited 55 | to the given family. 56 | 57 | Arguments: 58 | 59 | family -- str 60 | 61 | Return: list of odf_style 62 | """ 63 | result = [] 64 | for context in self._get_style_contexts(family): 65 | if context is None: 66 | continue 67 | result.extend(context.get_styles(family=family)) 68 | return result 69 | 70 | #get_style_list = obsolete('get_style_list', get_styles) 71 | 72 | 73 | def get_style(self, family, name_or_element=None, display_name=None): 74 | """Return the style uniquely identified by the name/family pair. If 75 | the argument is already a style object, it will return it. 76 | 77 | If the name is None, the default style is fetched. 78 | 79 | If the name is not the internal name but the name you gave in the 80 | desktop application, use display_name instead. 81 | 82 | Arguments: 83 | 84 | family -- 'paragraph', 'text', 'graphic', 'table', 'list', 85 | 'number' 86 | 87 | name_or_element -- unicode or odf_style 88 | 89 | display_name -- unicode 90 | 91 | Return: odf_style or None if not found 92 | """ 93 | for context in self._get_style_contexts(family): 94 | if context is None: 95 | continue 96 | style = context.get_style(family, 97 | name_or_element=name_or_element, 98 | display_name=display_name) 99 | if style is not None: 100 | return style 101 | return None 102 | -------------------------------------------------------------------------------- /test/use_case3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Jerome Dumonteil 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from os import mkdir 29 | from os.path import join, exists 30 | 31 | # Import from lpod 32 | from lpod import __version__, __installation_path__ 33 | from lpod.document import odf_new_document 34 | from lpod.table import odf_create_cell, odf_create_row 35 | from lpod.table import odf_create_table 36 | from lpod.style import odf_create_table_cell_style 37 | from lpod.style import make_table_cell_border_string 38 | from lpod.style import odf_create_style, rgb2hex 39 | 40 | # Hello messages 41 | print 'lpod installation test' 42 | print ' Version : %s' % __version__ 43 | print ' Installation path : %s' % __installation_path__ 44 | print 45 | print 'Generating test_output/use_case3.ods ...' 46 | 47 | 48 | document = odf_new_document('spreadsheet') 49 | body = document.get_body() 50 | table = odf_create_table(u'use_case3') 51 | 52 | for y in xrange(0, 256, 8): 53 | row = odf_create_row() 54 | for x in xrange(0, 256, 32): 55 | cell_value = (x, y, (x+y) % 256 ) 56 | border_rl = make_table_cell_border_string( 57 | thick = '0.20cm', 58 | color = 'white' 59 | ) 60 | border_bt = make_table_cell_border_string( 61 | thick = '0.80cm', 62 | color = 'white', 63 | ) 64 | style = odf_create_table_cell_style( 65 | color = 'grey' , 66 | background_color = cell_value, 67 | border_right = border_rl, 68 | border_left = border_rl, 69 | border_bottom = border_bt, 70 | border_top = border_bt, 71 | ) 72 | name = document.insert_style(style=style, automatic=True) 73 | cell = odf_create_cell(value=rgb2hex(cell_value), style=name) 74 | row.append_cell(cell) 75 | table.append_row(row) 76 | 77 | row_style = odf_create_style('table-row', height='1.80cm') 78 | name_style_row = document.insert_style(style=row_style, automatic=True) 79 | for row in table.get_rows(): 80 | row.set_style(name_style_row) 81 | table.set_row(row.y, row) 82 | 83 | col_style = odf_create_style('table-column', width='3.6cm') 84 | name = document.insert_style(style=col_style, automatic=True) 85 | for column in table.get_columns(): 86 | column.set_style(col_style) 87 | table.set_column(column.x, column) 88 | 89 | body.append(table) 90 | 91 | if not exists('test_output'): 92 | mkdir('test_output') 93 | document.save(join('test_output','use_case3.ods'), pretty=True) 94 | -------------------------------------------------------------------------------- /lpod/heading.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2013 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from re import sub 29 | 30 | # Import from lpod 31 | from paragraph import odf_paragraph 32 | from element import register_element_class, odf_create_element 33 | 34 | 35 | def odf_create_heading(level, text=None, restart_numbering=False, 36 | start_value=None, suppress_numbering=False, 37 | style=None): 38 | """Create a heading element of the given style and level, containing the 39 | optional given text. 40 | 41 | Level count begins at 1. 42 | 43 | Arguments: 44 | 45 | level -- int 46 | 47 | text -- unicode 48 | 49 | restart_numbering -- bool 50 | 51 | start_value -- int 52 | 53 | style -- unicode 54 | 55 | Return: odf_element 56 | """ 57 | data = '' 58 | element = odf_create_element(data % level) 59 | if text: 60 | element.set_text(text) 61 | if restart_numbering: 62 | element.set_attribute('text:restart-numbering', 'true') 63 | if start_value: 64 | element.set_attribute('text:start-value', '%s' % start_value) 65 | if suppress_numbering: 66 | element.set_attribute('text:suppress-numbering', 'true') 67 | if style: 68 | element.set_style(style) 69 | return element 70 | 71 | 72 | 73 | class odf_heading(odf_paragraph): 74 | """Specialised element for headings, which themselves are Specialised 75 | paragraphs. 76 | """ 77 | 78 | def get_formatted_text(self, context=None): 79 | if not context: 80 | context = { 'document': None, 81 | 'footnotes': [], 82 | 'endnotes': [], 83 | 'annotations': [], 84 | 'rst_mode': False, 85 | 'img_counter': 0, 86 | 'images': [], 87 | 'no_img_level': 0} 88 | context['no_img_level'] += 1 89 | title = odf_paragraph.get_formatted_text(self, context) 90 | context['no_img_level'] -= 1 91 | title = title.strip() 92 | title = sub(r'\s+', ' ', title) 93 | 94 | # No rst_mode ? 95 | if not context["rst_mode"]: 96 | return title 97 | # If here in rst_mode! 98 | 99 | # Get the level, max 5! 100 | LEVEL_STYLES = u"#=-~`+^°'." 101 | level = self.get_outline_level() 102 | if level > len(LEVEL_STYLES): 103 | raise ValueError, "Too many levels of heading" 104 | 105 | # And return the result 106 | result = [u'\n', title, u'\n', LEVEL_STYLES[level - 1] * len(title), 107 | u'\n'] 108 | return u''.join(result) 109 | 110 | 111 | 112 | register_element_class('text:h', odf_heading) 113 | -------------------------------------------------------------------------------- /test/test_draw_page.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.document import odf_get_document 32 | from lpod.draw_page import odf_create_draw_page, odf_draw_page 33 | 34 | 35 | class TestDrawPage(TestCase): 36 | 37 | def setUp(self): 38 | self.document = document = odf_get_document('samples/example.odp') 39 | self.body = document.get_body() 40 | 41 | 42 | def test_create_simple_page(self): 43 | element = odf_create_draw_page('id1') 44 | expected = '' 45 | self.assertEqual(element.serialize(), expected) 46 | 47 | 48 | def test_create_complex_page(self): 49 | element = odf_create_draw_page('id1', name=u"Introduction", 50 | master_page='prs-novelty', 51 | presentation_page_layout='AL1T0', 52 | style='dp1') 53 | expected = ('') 57 | self.assertEqual(element.serialize(), expected) 58 | 59 | 60 | def test_get_draw_page_list(self): 61 | body = self.body 62 | result = body.get_draw_pages() 63 | self.assertEqual(len(result), 2) 64 | 65 | 66 | def test_get_draw_page_list_style(self): 67 | body = self.body.clone() 68 | result = body.get_draw_pages(style='dp1') 69 | self.assertEqual(len(result), 2) 70 | result = body.get_draw_pages(style='dp2') 71 | self.assertEqual(len(result), 0) 72 | 73 | 74 | def test_odf_draw_page(self): 75 | body = self.body 76 | draw_page = body.get_draw_page() 77 | self.assert_(isinstance(draw_page, odf_draw_page)) 78 | 79 | 80 | def test_get_draw_page_by_name(self): 81 | body = self.body.clone() 82 | good = body.get_draw_page(name=u"Titre") 83 | self.assertNotEqual(good, None) 84 | bad = body.get_draw_page(name=u"Conclusion") 85 | self.assertEqual(bad, None) 86 | 87 | 88 | def test_get_page_name(self): 89 | body = self.body 90 | page = body.get_draw_page(name=u"Titre") 91 | self.assertEqual(page.get_name(), u"Titre") 92 | 93 | 94 | def test_set_page_name(self): 95 | body = self.body.clone() 96 | page = body.get_draw_page(position=0) 97 | name = u"Intitulé" 98 | self.assertNotEqual(page.get_name(), name) 99 | page.set_name(u"Intitulé") 100 | self.assertEqual(page.get_name(), name) 101 | 102 | 103 | 104 | if __name__ == '__main__': 105 | main() 106 | -------------------------------------------------------------------------------- /documentation/html/search.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Search — lpOD-python (version: 1.1.7) documentation 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 49 | 50 |
51 |
52 |
53 |
54 | 55 |

Search

56 |
57 | 58 |

59 | Please activate JavaScript to enable the search 60 | functionality. 61 |

62 |
63 |

64 | From here you can search these documents. Enter your search 65 | words into the box below and click "search". Note that the search 66 | function will automatically search for all of the words. Pages 67 | containing fewer words won't appear in the result list. 68 |

69 |
70 | 71 | 72 | 73 |
74 | 75 |
76 | 77 |
78 | 79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | 100 | 105 | 106 | -------------------------------------------------------------------------------- /documentation/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 16 | .highlight .go { color: #333333 } /* Generic.Output */ 17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #902000 } /* Keyword.Type */ 27 | .highlight .m { color: #208050 } /* Literal.Number */ 28 | .highlight .s { color: #4070a0 } /* Literal.String */ 29 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 30 | .highlight .nb { color: #007020 } /* Name.Builtin */ 31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #60add5 } /* Name.Constant */ 33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #007020 } /* Name.Exception */ 36 | .highlight .nf { color: #06287e } /* Name.Function */ 37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /scripts/lpod-meta.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | # Import from the standard library 28 | from optparse import OptionParser 29 | from sys import exit, stdin 30 | 31 | # Import from lpod 32 | from lpod import __version__, ODF_META 33 | from lpod.document import odf_get_document 34 | from lpod.datatype import Date, DateTime 35 | from lpod.scriptutils import printerr 36 | 37 | 38 | 39 | def set_metadata(doc, set_list): 40 | meta = doc.get_part(ODF_META) 41 | for set_info in set_list: 42 | if '=' not in set_info: 43 | printerr('Bad argument -s "%s" (must be "name=value")' % set_info) 44 | exit(1) 45 | name, value = set_info.split('=', 1) 46 | name = name.lower().strip() 47 | value = value.strip() 48 | 49 | if name in ("title", "subject", "initial_creator", 50 | "keywords", "generator", "description"): 51 | value = value.decode(stdin.encoding) 52 | func = meta.__getattribute__('set_' + name) 53 | func(value) 54 | elif name == "language": 55 | meta.set_language(value) 56 | elif name in ("modification_date", "creation_date"): 57 | try: 58 | if 'T' in value: 59 | date = DateTime.decode(value) 60 | else: 61 | date = Date.decode(value) 62 | except ValueError, error: 63 | printerr('Bad argument -s "%s": %s' % (set_info, error)) 64 | exit(1) 65 | func = meta.__getattribute__('set_' + name) 66 | func(date) 67 | else: 68 | printerr('Unknown metadata name "%s", please choose: ' % name) 69 | printerr(" title, subject, initial_creator, keywords, " 70 | "generator, description, modification_date or " 71 | "creation_date") 72 | exit(1) 73 | 74 | # XXX User defined metadata? 75 | 76 | doc.save() 77 | 78 | 79 | 80 | if __name__ == '__main__': 81 | # Options initialisation 82 | usage = "%prog [options] " 83 | description = "Dump metadata informations on the standard output" 84 | parser = OptionParser(usage, version=__version__, description=description) 85 | 86 | # Set 87 | help = 'Replace and/or set the metadata NAME with the value VALUE' 88 | parser.add_option('-s', '--set', action='append', dest='set_list', 89 | metavar='NAME=VALUE', help=help) 90 | 91 | # Parse ! 92 | options, args = parser.parse_args() 93 | 94 | # Open the document 95 | if len(args) != 1: 96 | parser.print_help() 97 | exit(1) 98 | doc = odf_get_document(args[0]) 99 | 100 | if options.set_list: 101 | # Set metadata, ... 102 | set_metadata(doc, options.set_list) 103 | else: 104 | # Dump 105 | print doc.get_formated_meta().encode('utf-8') 106 | -------------------------------------------------------------------------------- /lpod/link.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2013 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # Jerome Dumonteil 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from lpod 29 | from element import odf_element, odf_create_element, register_element_class 30 | from paragraph import paragraph_base 31 | 32 | 33 | 34 | def odf_create_link(url, name=None, title=None, text=None, target_frame=None, 35 | style=None, visited_style=None): 36 | """Return a text:a odf_element. 37 | 38 | Arguments: 39 | 40 | url -- str 41 | 42 | name -- unicode 43 | 44 | title -- unicode 45 | 46 | text -- unicode 47 | 48 | target_frame -- '_self', '_blank', '_parent', '_top' 49 | 50 | style -- string 51 | 52 | visited_style -- string 53 | """ 54 | link = odf_create_element('text:a') 55 | link.set_url(url) 56 | if name is not None: 57 | link.set_name(name) 58 | if title is not None: 59 | link.set_title(title) 60 | if text is not None: 61 | link.set_text(text) 62 | #if target_frame is None: 63 | # target_frame = '_self' 64 | if target_frame is not None: 65 | link.set_target_frame(target_frame) 66 | if target_frame == '_blank': 67 | link.set_show('new') 68 | else: 69 | link.set_show('replace') 70 | if style is not None: 71 | link.set_style(style) 72 | if visited_style is not None: 73 | link.set_visited_style(visited_style) 74 | return link 75 | 76 | 77 | 78 | class odf_link(paragraph_base): 79 | 80 | def get_name(self): 81 | return self.get_attribute('office:name') 82 | 83 | 84 | def set_name(self, name): 85 | return self.set_attribute('office:name', name) 86 | 87 | def get_url(self): 88 | return self.get_attribute('xlink:href') 89 | 90 | 91 | def set_url(self, url): 92 | return self.set_attribute('xlink:href', url) 93 | 94 | 95 | def get_title(self): 96 | return self.get_attribute('office:title') 97 | 98 | 99 | def set_title(self, title): 100 | return self.set_attribute('office:title', title) 101 | 102 | 103 | def get_target_frame(self): 104 | return self.get_attribute('office:target-frame-name') 105 | 106 | 107 | def set_target_frame(self, name): 108 | return self.set_style_attribute('office:target-frame-name', name) 109 | 110 | 111 | def get_show(self): 112 | return self.get_attribute('xlink:show') 113 | 114 | 115 | def set_show(self, value): 116 | """'new' or 'replace' 117 | """ 118 | return self.set_attribute('xlink:show', value) 119 | 120 | 121 | def get_visited_style(self): 122 | return self.get_attribute('text:visited-style-name') 123 | 124 | 125 | def set_visited_style(self, name): 126 | attribute = 'text:visited-style-name' 127 | return self.set_style_attribute(attribute, name) 128 | 129 | 130 | register_element_class('text:a', odf_link) 131 | -------------------------------------------------------------------------------- /lpod/smil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | """Implementation of SMIL 28 | 29 | We can find more informations here: http://www.w3.org/TR/SMIL20/ 30 | """ 31 | 32 | # Import from lpod 33 | from element import odf_create_element 34 | 35 | 36 | 37 | def odf_create_anim_par(presentation_node_type=None, smil_begin=None): 38 | """This element is a container for SMIL Presentation Animations. 39 | 40 | Arguments: 41 | 42 | presentation_node_type -- default, on-click, with-previous, 43 | after-previous, timing-root, main-sequence 44 | and interactive-sequence 45 | 46 | smil_begin -- indefinite, 10s, [id].click, [id].begin 47 | """ 48 | element = odf_create_element('anim:par') 49 | if presentation_node_type: 50 | element.set_attribute('presentation:node-type', presentation_node_type) 51 | if smil_begin: 52 | element.set_attribute('smil:begin', smil_begin) 53 | return element 54 | 55 | 56 | 57 | def odf_create_anim_seq(presentation_node_type=None): 58 | """This element is a container for SMIL Presentation Animations. Animations 59 | inside this block are executed after the slide has executed its initial 60 | transition. 61 | 62 | Arguments: 63 | 64 | presentation_node_type -- default, on-click, with-previous, 65 | after-previous, timing-root, main-sequence 66 | and interactive-sequence 67 | """ 68 | element = odf_create_element('anim:seq') 69 | if presentation_node_type: 70 | element.set_attribute('presentation:node-type', presentation_node_type) 71 | return element 72 | 73 | 74 | 75 | def odf_create_anim_transitionFilter(smil_dur=None, smil_type=None, 76 | smil_subtype=None, smil_direction=None, 77 | smil_fadeColor=None, smil_mode=None): 78 | """ 79 | Used to make a beautiful transition between two frames. 80 | 81 | Arguments: 82 | smil_dur -- XXX complete me 83 | smil_type and smil_subtype -- see http://www.w3.org/TR/SMIL20/smil-transitions.html#TransitionEffects-Appendix to get a list of all types/subtypes 84 | smil_direction -- forward, reverse 85 | smil_fadeColor -- forward, reverse 86 | smil_mode -- in, out 87 | """ 88 | 89 | element = odf_create_element('anim:transitionFilter') 90 | 91 | if smil_dur: 92 | element.set_attribute('smil:dur', smil_dur) 93 | if smil_type: 94 | element.set_attribute('smil:type', smil_type) 95 | if smil_subtype: 96 | element.set_attribute('smil:subtype', smil_subtype) 97 | if smil_direction: 98 | element.set_attribute('smil:direction', smil_direction) 99 | if smil_fadeColor: 100 | element.set_attribute('smil:fadeColor', smil_fadeColor) 101 | if smil_mode: 102 | element.set_attribute('smil:mode', smil_mode) 103 | return element 104 | 105 | -------------------------------------------------------------------------------- /scripts/lpod-mm2odt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: Hervé Cauwelier 7 | # Romain Gauthier 8 | # 9 | # This file is part of Lpod (see: http://lpod-project.net). 10 | # Lpod is free software; you can redistribute it and/or modify it under 11 | # the terms of either: 12 | # 13 | # a) the GNU General Public License as published by the Free Software 14 | # Foundation, either version 3 of the License, or (at your option) 15 | # any later version. 16 | # Lpod is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # You should have received a copy of the GNU General Public License 21 | # along with Lpod. If not, see . 22 | # 23 | # b) the Apache License, Version 2.0 (the "License"); 24 | # you may not use this file except in compliance with the License. 25 | # You may obtain a copy of the License at 26 | # http://www.apache.org/licenses/LICENSE-2.0 27 | # 28 | 29 | # Import from the standard library 30 | from optparse import OptionParser 31 | from os.path import basename, splitext 32 | from sys import exit 33 | 34 | # Import from lxml 35 | from lxml.etree import parse 36 | 37 | # Import from lpod 38 | from lpod import __version__ 39 | from lpod.toc import odf_create_toc 40 | from lpod.document import odf_new_document 41 | from lpod.heading import odf_create_heading 42 | from lpod.scriptutils import add_option_output, check_target_file 43 | 44 | 45 | def make_mm_structure(node, level): 46 | sub_struct = [] 47 | for sub_node in node.xpath('node'): 48 | sub_struct.append(make_mm_structure(sub_node, level + 1)) 49 | text = node.attrib['TEXT'] 50 | return (level, text, sub_struct) 51 | 52 | 53 | 54 | def make_document(structure, body): 55 | for level, text, struct in structure: 56 | # Create the heading with the corresponding level 57 | heading = odf_create_heading(level, text=text) 58 | # Add the heading to the document's body 59 | body.append(heading) 60 | make_document(struct, body) 61 | 62 | 63 | 64 | if __name__ == '__main__': 65 | # Options initialisation 66 | usage = '%prog [-o output.odt] ' 67 | description = 'Transform a mind-map file to an OpenDocument Text file.' 68 | parser = OptionParser(usage, version=__version__, description=description) 69 | # --output 70 | add_option_output(parser, complement="(.odt by default)") 71 | 72 | # Parse options 73 | options, args = parser.parse_args() 74 | if len(args) < 1: 75 | parser.print_help() 76 | exit(1) 77 | 78 | # Get the 2 paths 79 | inname = args[0] 80 | outname = options.output 81 | # Default value for the name of the output file. 82 | if not outname: 83 | mm_basename = basename(inname) 84 | outname = '%s.odt' % splitext(mm_basename)[0] 85 | # Check if the file already exists 86 | check_target_file(outname) 87 | 88 | # Open the XML file 89 | mm = parse(open(inname, 'rb')) 90 | # Get the first node of the mind map 91 | first_node = mm.xpath('/map/node')[0] 92 | # Make the structure 93 | mm_structure = make_mm_structure(first_node, 0) 94 | 95 | # Create a new ODT document 96 | document = odf_new_document('text') 97 | body = document.get_body() 98 | # Remove the default paragraph 99 | body.clear() 100 | # Begin with a TOC 101 | toc = odf_create_toc() 102 | body.append(toc) 103 | # Set the title 104 | meta = document.get_meta() 105 | meta.set_title(mm_structure[1]) 106 | # Make the document from the structure 107 | make_document(mm_structure[2], body) 108 | # Fill the TOC 109 | toc.toc_fill() 110 | 111 | # Save the document 112 | document.save(outname, pretty=True) 113 | # Feed back to the user 114 | print "`%s' created from `%s'" % (outname, inname) 115 | -------------------------------------------------------------------------------- /lpod/xmlpart.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from copy import deepcopy 30 | from cStringIO import StringIO 31 | 32 | # Import from lxml 33 | from lxml.etree import parse, tostring 34 | 35 | # Import from lpod 36 | from element import _make_odf_element 37 | #from utils import obsolete 38 | 39 | 40 | class odf_xmlpart(object): 41 | """Representation of an XML part. 42 | Abstraction of the XML library behind. 43 | """ 44 | def __init__(self, part_name, container): 45 | self.part_name = part_name 46 | self.container = container 47 | 48 | # Internal state 49 | self.__tree = None 50 | self.__root = None 51 | 52 | 53 | def __get_tree(self): 54 | if self.__tree is None: 55 | container = self.container 56 | part = container.get_part(self.part_name) 57 | self.__tree = parse(StringIO(part)) 58 | return self.__tree 59 | 60 | 61 | # 62 | # Public API 63 | # 64 | 65 | def get_root(self): 66 | if self.__root is None: 67 | tree = self.__get_tree() 68 | self.__root = _make_odf_element(tree.getroot()) 69 | return self.__root 70 | 71 | 72 | def get_elements(self, xpath_query): 73 | root = self.get_root() 74 | return root.xpath(xpath_query) 75 | 76 | #get_element_list = obsolete('get_element_list', get_elements) 77 | 78 | 79 | def get_element(self, xpath_query): 80 | result = self.get_elements(xpath_query) 81 | if not result: 82 | return None 83 | return result[0] 84 | 85 | 86 | def delete_element(self, child): 87 | child.delete() 88 | 89 | 90 | def xpath(self, xpath_query): 91 | """Apply XPath query to the XML part. Return list of odf_element or 92 | odf_text instances translated from the nodes found. 93 | """ 94 | root = self.get_root() 95 | return root.xpath(xpath_query) 96 | 97 | 98 | def clone(self): 99 | clone = object.__new__(self.__class__) 100 | for name in self.__dict__: 101 | if name == 'container': 102 | setattr(clone, name, self.container.clone()) 103 | elif name in ('_odf_xmlpart__tree',): 104 | setattr(clone, name, None) 105 | else: 106 | value = getattr(self, name) 107 | value = deepcopy(value) 108 | setattr(clone, name, value) 109 | return clone 110 | 111 | 112 | def serialize(self, pretty=False): 113 | tree = self.__get_tree() 114 | # Lxml declaration is too exotic to me 115 | data = [''] 116 | tree = tostring(tree, encoding='UTF-8', pretty_print=pretty) 117 | # Lxml with pretty_print is adding a empty line 118 | if pretty: 119 | tree = tree.strip() 120 | data.append(tree) 121 | return '\n'.join(data) 122 | -------------------------------------------------------------------------------- /test/use_case1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from csv import reader 30 | from os import listdir, mkdir 31 | from os.path import join, exists 32 | from mimetypes import guess_type 33 | 34 | # Import from PIL 35 | from PIL import Image 36 | 37 | # Import from lpod 38 | from lpod import __version__, __installation_path__ 39 | from lpod.document import odf_new_document 40 | from lpod.element import FIRST_CHILD 41 | from lpod.frame import odf_create_frame 42 | from lpod.heading import odf_create_heading 43 | from lpod.image import odf_create_image 44 | from lpod.paragraph import odf_create_paragraph 45 | from lpod.table import odf_create_cell, odf_create_row 46 | from lpod.table import odf_create_column, odf_create_table 47 | 48 | 49 | # Hello messages 50 | print 'lpod installation test' 51 | print ' Version : %s' % __version__ 52 | print ' Installation path : %s' % __installation_path__ 53 | print 54 | print 'Generating test_output/use_case1.odt ...' 55 | 56 | 57 | # Go 58 | document = odf_new_document('text') 59 | body = document.get_body() 60 | 61 | for numero, filename in enumerate(listdir('samples')): 62 | # Heading 63 | heading = odf_create_heading(1, text=unicode(filename, 'utf-8')) 64 | body.append(heading) 65 | path = join('samples', filename) 66 | mimetype, _ = guess_type(path) 67 | if mimetype is None: 68 | mimetype = 'application/octet-stream' 69 | if mimetype.startswith('image/'): 70 | # Add the image 71 | internal_name = 'Pictures/' + filename 72 | image = Image.open(path) 73 | width, height = image.size 74 | paragraph = odf_create_paragraph('Standard') 75 | # 72 ppp 76 | frame = odf_create_frame('frame_%d' % numero, 'Graphics', 77 | str(width / 72.0) + 'in', 78 | str(height / 72.0) + 'in') 79 | image = odf_create_image(internal_name) 80 | frame.append(image) 81 | paragraph.append(frame) 82 | body.append(paragraph) 83 | 84 | # And store the data 85 | container = document.container 86 | container.set_part(internal_name, open(path).read()) 87 | elif mimetype in ('text/csv', 'text/comma-separated-values'): 88 | table = odf_create_table(u"table %d" % numero, style=u"Standard") 89 | csv = reader(open(path)) 90 | for line in csv: 91 | size = len(line) 92 | row = odf_create_row() 93 | for value in line: 94 | cell = odf_create_cell(value) 95 | row.append_cell(cell) 96 | table.append_row(row) 97 | for i in xrange(size): 98 | column = odf_create_column(style=u"Standard") 99 | table.insert(column, FIRST_CHILD) 100 | body.append(table) 101 | else: 102 | paragraph = odf_create_paragraph(u"Not image / csv", 103 | style=u"Standard") 104 | body.append(paragraph) 105 | 106 | if not exists('test_output'): 107 | mkdir('test_output') 108 | document.save('test_output/use_case1.odt', pretty=True) 109 | -------------------------------------------------------------------------------- /test/test_heading.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from unittest import TestCase, main 29 | 30 | # Import from lpod 31 | from lpod.document import odf_get_document 32 | from lpod.heading import odf_create_heading, odf_heading 33 | 34 | 35 | class TestHeading(TestCase): 36 | 37 | def setUp(self): 38 | self.document = document = odf_get_document('samples/base_text.odt') 39 | self.body = document.get_body() 40 | 41 | 42 | def test_get_heading_list(self): 43 | body = self.body 44 | headings = body.get_headings() 45 | self.assertEqual(len(headings), 3) 46 | second = headings[1] 47 | text = second.get_text() 48 | self.assertEqual(text, u'Level 2 Title') 49 | 50 | 51 | def test_get_heading_list_style(self): 52 | body = self.body 53 | headings = body.get_headings(style='Heading_20_2') 54 | self.assertEqual(len(headings), 1) 55 | heading = headings[0] 56 | text = heading.get_text() 57 | self.assertEqual(text, u'Level 2 Title') 58 | 59 | 60 | def test_get_heading_list_level(self): 61 | body = self.body 62 | headings = body.get_headings(outline_level=2) 63 | self.assertEqual(len(headings), 1) 64 | heading = headings[0] 65 | text = heading.get_text() 66 | self.assertEqual(text, u'Level 2 Title') 67 | 68 | 69 | def test_get_heading_list_style_level(self): 70 | body = self.body 71 | headings = body.get_headings(style='Heading_20_2', outline_level=2) 72 | self.assertEqual(len(headings), 1) 73 | heading = headings[0] 74 | text = heading.get_text() 75 | self.assertEqual(text, u'Level 2 Title') 76 | 77 | 78 | def test_get_heading_list_context(self): 79 | body = self.body 80 | section2 = body.get_section(position=1) 81 | headings = section2.get_headings() 82 | self.assertEqual(len(headings), 1) 83 | heading = headings[0] 84 | text = heading.get_text() 85 | self.assertEqual(text, u"First Title of the Second Section"); 86 | 87 | 88 | def test_odf_heading(self): 89 | body = self.body 90 | heading = body.get_heading() 91 | self.assert_(isinstance(heading, odf_heading)) 92 | 93 | 94 | def test_get_heading(self): 95 | body = self.body 96 | heading = body.get_heading(position=1) 97 | text = heading.get_text() 98 | self.assertEqual(text, u'Level 2 Title') 99 | 100 | 101 | def test_get_heading_level(self): 102 | body = self.body 103 | heading = body.get_heading(outline_level=2) 104 | text = heading.get_text() 105 | self.assertEqual(text, u'Level 2 Title') 106 | 107 | 108 | def test_insert_heading(self): 109 | body = self.body.clone() 110 | heading = odf_create_heading(2, u'An inserted heading', 111 | style='Heading_20_2') 112 | body.append(heading) 113 | last_heading = body.get_headings()[-1] 114 | self.assertEqual(last_heading.get_text(), u'An inserted heading') 115 | 116 | 117 | 118 | if __name__ == '__main__': 119 | main() 120 | -------------------------------------------------------------------------------- /test/test_manifest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from unittest import TestCase, main 30 | 31 | # Import from lpod 32 | from lpod.const import ODF_PRESENTATION, ODF_MANIFEST 33 | from lpod.document import odf_get_document 34 | from lpod.manifest import odf_manifest 35 | 36 | 37 | class ManifestTestCase(TestCase): 38 | 39 | def setUp(self): 40 | self.document = odf_get_document('samples/frame_image.odp') 41 | self.manifest = self.document.get_part(ODF_MANIFEST) 42 | self.image_path = 'Pictures/10000000000001D40000003C8B3889D9.png' 43 | 44 | 45 | def test_get_manifest(self): 46 | self.assert_(type(self.manifest) is odf_manifest) 47 | 48 | 49 | def test_get_path_list(self): 50 | results = self.manifest.get_paths() 51 | self.assertEqual(len(results), 20) 52 | 53 | 54 | def test_get_path_media_list(self): 55 | results = self.manifest.get_path_medias() 56 | self.assertEqual(len(results), 20) 57 | root = results[0] 58 | self.assertEqual(root, ('/', ODF_PRESENTATION)) 59 | 60 | 61 | def test_get_media_type_root(self): 62 | self.assertEqual(self.manifest.get_media_type('/'), ODF_PRESENTATION) 63 | 64 | 65 | def test_get_media_type_directory(self): 66 | self.assertEqual(self.manifest.get_media_type('Pictures/'), '') 67 | 68 | 69 | def test_get_media_type_other(self): 70 | path = self.image_path 71 | self.assertEqual(self.manifest.get_media_type(path), 'image/png') 72 | 73 | 74 | def test_get_media_type_missing(self): 75 | self.assert_(self.manifest.get_media_type('LpOD') is None) 76 | 77 | 78 | def test_set_media_type(self): 79 | manifest = self.manifest.clone() 80 | path = self.image_path 81 | self.assertEqual(manifest.get_media_type(path), 'image/png') 82 | manifest.set_media_type(path, 'image/jpeg') 83 | self.assertEqual(manifest.get_media_type(path), 'image/jpeg') 84 | 85 | 86 | def test_set_media_type_missing(self): 87 | manifest = self.manifest.clone() 88 | self.assertRaises(KeyError, manifest.set_media_type, 'LpOD', '') 89 | 90 | 91 | def test_add_full_path(self): 92 | manifest = self.manifest.clone() 93 | self.assert_(manifest.get_media_type('LpOD') is None) 94 | manifest.add_full_path('LpOD', '') 95 | self.assertEqual(manifest.get_media_type('LpOD'), '') 96 | 97 | 98 | def test_add_full_path_existing(self): 99 | manifest = self.manifest.clone() 100 | path = self.image_path 101 | self.assertEqual(manifest.get_media_type(path), 'image/png') 102 | manifest.add_full_path(path, 'image/jpeg') 103 | self.assertEqual(manifest.get_media_type(path), 'image/jpeg') 104 | 105 | 106 | def test_del_full_path(self): 107 | manifest = self.manifest.clone() 108 | path = self.image_path 109 | self.assertEqual(manifest.get_media_type(path), 'image/png') 110 | manifest.del_full_path(path) 111 | self.assert_(manifest.get_media_type(path) is None) 112 | 113 | 114 | 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /lpod/manifest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: David Versmisse 6 | # Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from lpod 29 | from element import odf_create_element 30 | #from utils import obsolete 31 | from xmlpart import odf_xmlpart 32 | 33 | 34 | def odf_create_file_entry(full_path, media_type): 35 | data = ('') 37 | return odf_create_element(data % (media_type, full_path)) 38 | 39 | 40 | 41 | class odf_manifest(odf_xmlpart): 42 | 43 | # 44 | # Public API 45 | # 46 | 47 | def get_paths(self): 48 | """Return the list of full paths in the manifest. 49 | 50 | Return: list of unicode 51 | """ 52 | expr = '//manifest:file-entry/attribute::manifest:full-path' 53 | return self.xpath(expr) 54 | 55 | #get_path_list = obsolete('get_path_list', get_paths) 56 | 57 | 58 | def get_path_medias(self): 59 | """Return the list of (full_path, media_type) pairs in the manifest. 60 | 61 | Return: list of (unicode, str) tuples 62 | """ 63 | expr = '//manifest:file-entry' 64 | result = [] 65 | for file_entry in self.xpath(expr): 66 | result.append((file_entry.get_attribute('manifest:full-path'), 67 | file_entry.get_attribute('manifest:media-type'))) 68 | return result 69 | 70 | #get_path_media_list = obsolete('get_path_media_list', get_path_medias) 71 | 72 | 73 | def get_media_type(self, full_path): 74 | """Get the media type of an existing path. 75 | 76 | Return: str 77 | """ 78 | expr = ('//manifest:file-entry[attribute::manifest:full-path="%s"]' 79 | '/attribute::manifest:media-type') 80 | result = self.xpath(expr % full_path) 81 | if not result: 82 | return None 83 | return result[0] 84 | 85 | 86 | def set_media_type(self, full_path, media_type): 87 | """Set the media type of an existing path. 88 | 89 | Arguments: 90 | 91 | full_path -- unicode 92 | 93 | media_type -- str 94 | """ 95 | expr = '//manifest:file-entry[attribute::manifest:full-path="%s"]' 96 | result = self.xpath(expr % full_path) 97 | if not result: 98 | raise KeyError('path "%s" not found' % full_path) 99 | file_entry = result[0] 100 | file_entry.set_attribute('manifest:media-type', str(media_type)) 101 | 102 | 103 | def add_full_path(self, full_path, media_type=''): 104 | # Existing? 105 | existing = self.get_media_type(full_path) 106 | if existing is not None: 107 | self.set_media_type(full_path, media_type) 108 | root = self.get_root() 109 | file_entry = odf_create_file_entry(full_path, media_type) 110 | root.append(file_entry) 111 | 112 | 113 | def del_full_path(self, full_path): 114 | expr = '//manifest:file-entry[attribute::manifest:full-path="%s"]' 115 | result = self.xpath(expr % full_path) 116 | if not result: 117 | raise KeyError('path "%s" not found' % full_path) 118 | file_entry = result[0] 119 | root = self.get_root() 120 | root.delete(file_entry) 121 | -------------------------------------------------------------------------------- /doc_make/Makefile: -------------------------------------------------------------------------------- 1 | ##################################### 2 | # Makefile for Sphinx documentation # 3 | ##################################### 4 | 5 | 6 | # General options 7 | # --------------- 8 | 9 | # Git repository 10 | GIT_VERSION = $(shell ../release.py) 11 | 12 | # Python path 13 | PYTHON = $(shell cat ../python_path.txt) 14 | 15 | # You can set these variables from the command line. 16 | SPHINXOPTS = 17 | SPHINXBUILD = $(PYTHON) sphinx-link.py 18 | PAPER = 19 | 20 | # Internal variables. 21 | PAPEROPT_a4 = -D latex_paper_size=a4 22 | PAPEROPT_letter = -D latex_paper_size=letter 23 | ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 24 | 25 | .PHONY: help clean html latex pdf pdf-figures png-figures changes linkcheck \ 26 | release lpod-check 27 | 28 | help: 29 | @echo "Please use \`make ' where is one of" 30 | @echo " html to make standalone HTML files" 31 | # @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | # @echo " pdf to make PDF files, you can set PAPER=a4 or PAPER=letter" 33 | # @echo " changes to make an overview over all changed/added/deprecated items" 34 | # @echo " linkcheck to check all external links for integrity" 35 | # @echo " release to make html/pdf and store the files in two tar.gz" 36 | 37 | clean: 38 | -rm -rf build 39 | -rm -rf lpod-docs-*.tgz 40 | -rm -rf figures 41 | -rm -rf autodocs 42 | 43 | lpod-check: 44 | @if [ x${PYTHON} == "x" ]; then \ 45 | echo "Please, you must first install lpod"; \ 46 | exit 1; \ 47 | fi 48 | 49 | html: lpod-check png-figures 50 | mkdir -p build/html build/doctrees 51 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html 52 | @echo 53 | @echo "Build finished. The HTML pages are in build/html." 54 | 55 | latex: lpod-check pdf-figures 56 | mkdir -p build/latex build/doctrees 57 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex 58 | @echo 59 | @echo "Build finished; the LaTeX files are in .build/latex." 60 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 61 | "run these through (pdf)latex." 62 | 63 | pdf: latex 64 | cd build/latex && make all-pdf && cp lpod.pdf ../../lpod-$(GIT_VERSION).pdf 65 | rm -f lpod.pdf 66 | ln -s lpod-$(GIT_VERSION).pdf lpod.pdf 67 | @echo 68 | @echo "Your PDF is available in lpod.pdf" 69 | 70 | changes: 71 | mkdir -p build/changes build/doctrees 72 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes 73 | @echo 74 | @echo "The overview file is in build/changes." 75 | 76 | linkcheck: 77 | mkdir -p build/linkcheck build/doctrees 78 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck 79 | @echo 80 | @echo "Link check complete; look for any errors in the above output " \ 81 | "or in build/linkcheck/output.txt." 82 | 83 | release: pdf html 84 | cd build; \ 85 | mv html lpod-docs-$(GIT_VERSION); \ 86 | tar czf ../lpod-docs-$(GIT_VERSION).tgz lpod-docs-$(GIT_VERSION); \ 87 | mv lpod-docs-$(GIT_VERSION) html 88 | @echo 89 | @echo "doc is available ./lpod-docs-$(GIT_VERSION).tgz" 90 | 91 | 92 | # Figures conversion 93 | # ------------------ 94 | 95 | SRC_NAMES=$(wildcard figures-src/*) 96 | SRC_BASE_NAMES=$(basename $(SRC_NAMES)) 97 | TARGET_BASE_NAMES=$(patsubst figures-src/%, figures/%, $(SRC_BASE_NAMES)) 98 | 99 | PDF_NAMES=$(addsuffix .pdf, $(TARGET_BASE_NAMES)) 100 | PNG_NAMES=$(addsuffix .png, $(TARGET_BASE_NAMES)) 101 | 102 | pdf-figures: figures $(PDF_NAMES) 103 | 104 | png-figures: figures $(PNG_NAMES) 105 | 106 | figures: 107 | mkdir -p figures 108 | 109 | # To PDF rules 110 | 111 | figures/%.eps: figures-src/%.png 112 | convert $< -compress jpeg eps2:$@ 113 | 114 | figures/%.eps: figures-src/%.jpg 115 | convert -units PixelsPerInch -density 72 $< eps2:$@ 116 | 117 | figures/%.eps: figures-src/%.svg 118 | inkscape -z $< -E $@ 119 | 120 | figures/%.eps: figures-src/%.fig 121 | fig2dev -L eps $< $@ 122 | 123 | figures/%.eps: figures-src/%.dot 124 | dot -Tps $< -o $@ 125 | 126 | figures/%.eps: figures-src/%.dia 127 | dia $< -e $@ 128 | 129 | %.pdf: %.eps 130 | epstopdf $< 131 | 132 | # To PNG rules 133 | 134 | figures/%.png: figures-src/%.png 135 | cp $< $@ 136 | 137 | figures/%.png: figures-src/%.jpg 138 | convert $< $@ 139 | 140 | figures/%.png: figures-src/%.svg 141 | inkscape -z $< -e $@ 142 | 143 | figures/%.png: figures-src/%.dot 144 | dot -Tpng $< -o $@ 145 | 146 | figures/%.png: figures-src/%.dia 147 | dia $< -e $@ -t cairo-png 148 | -------------------------------------------------------------------------------- /test/test_xmlpart.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # David Versmisse 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the Standard Library 29 | from unittest import TestCase, main 30 | 31 | # Import from the XML Library 32 | from lxml.etree import _ElementTree 33 | 34 | # Import from lpod 35 | from lpod.const import ODF_CONTENT 36 | from lpod.container import odf_get_container 37 | from lpod.element import odf_create_element, odf_element 38 | from lpod.xmlpart import odf_xmlpart 39 | 40 | 41 | class XmlPartTestCase(TestCase): 42 | 43 | def setUp(self): 44 | self.container = odf_get_container('samples/example.odt') 45 | 46 | 47 | def tearDown(self): 48 | del self.container 49 | 50 | 51 | def test_get_element_list(self): 52 | content_part = odf_xmlpart(ODF_CONTENT, self.container) 53 | elements = content_part.get_elements('//text:p') 54 | # The annotation paragraph is counted 55 | self.assertEqual(len(elements), 8) 56 | 57 | 58 | def test_tree(self): 59 | # Testing a private but important method 60 | content = odf_xmlpart(ODF_CONTENT, self.container) 61 | tree = content._odf_xmlpart__get_tree() 62 | self.assert_(isinstance(tree, _ElementTree)) 63 | self.assertNotEqual(content._odf_xmlpart__tree, None) 64 | 65 | 66 | def test_root(self): 67 | content = odf_xmlpart(ODF_CONTENT, self.container) 68 | root = content.get_root() 69 | self.assert_(isinstance(root, odf_element)) 70 | self.assertEqual(root.get_tag(), "office:document-content") 71 | self.assertNotEqual(content._odf_xmlpart__root, None) 72 | 73 | 74 | def test_serialize(self): 75 | container = self.container 76 | content_bytes = container.get_part(ODF_CONTENT) 77 | content_part = odf_xmlpart(ODF_CONTENT, container) 78 | # differences with lxml 79 | serialized = content_part.serialize().replace("'", "'") 80 | # XXX OOo is adding two carriage returns behind the XML declaration 81 | serialized = serialized.replace('\n', 82 | '\n\n') 83 | self.assertEqual(content_bytes, serialized) 84 | 85 | 86 | def test_pretty_serialize(self): 87 | # With pretty = True 88 | element = odf_create_element('spam') 89 | serialized = element.serialize(pretty=True) 90 | expected = ('\n' 91 | ' spam\n' 92 | ' \n' 93 | '\n') 94 | self.assertEqual(serialized, expected) 95 | 96 | 97 | def test_clone(self): 98 | # Testing that the clone works on subclasses too 99 | from lpod.content import odf_content 100 | container = self.container 101 | content = odf_content(ODF_CONTENT, container) 102 | clone = content.clone() 103 | self.assertEqual(clone.part_name, content.part_name) 104 | self.assertNotEqual(id(container), id(clone.container)) 105 | self.assertEqual(clone._odf_xmlpart__tree, None) 106 | 107 | 108 | def test_delete(self): 109 | container = self.container 110 | content = odf_xmlpart(ODF_CONTENT, container) 111 | paragraphs = content.get_elements('//text:p') 112 | for paragraph in paragraphs: 113 | content.delete_element(paragraph) 114 | serialized = content.serialize() 115 | self.assertEqual(serialized.count(' 6 | # Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Types and their default template 29 | ODF_TYPES = { 30 | 'text': 'templates/text.ott', 31 | 'spreadsheet': 'templates/spreadsheet.ots', 32 | 'presentation': 'templates/presentation.otp', 33 | # Follow the spec 34 | 'drawing': 'templates/drawing.otg', 35 | # Follow the mimetype 36 | 'graphics': 'templates/drawing.otg', 37 | # TODO 38 | #'chart': 'templates/chart.otc', 39 | #'image': 'templates/image.oti', 40 | #'formula': 'templates/image.otf', 41 | #'master': 'templates/image.odm', 42 | #'web': 'templates/image.oth', 43 | } 44 | 45 | 46 | ODF_TEXT = 'application/vnd.oasis.opendocument.text' 47 | ODF_TEXT_TEMPLATE = 'application/vnd.oasis.opendocument.text-template' 48 | ODF_SPREADSHEET = 'application/vnd.oasis.opendocument.spreadsheet' 49 | ODF_SPREADSHEET_TEMPLATE = 'application/vnd.oasis.opendocument.spreadsheet-template' 50 | ODF_PRESENTATION = 'application/vnd.oasis.opendocument.presentation' 51 | ODF_PRESENTATION_TEMPLATE = 'application/vnd.oasis.opendocument.presentation-template' 52 | ODF_DRAWING = 'application/vnd.oasis.opendocument.graphics' 53 | ODF_DRAWING_TEMPLATE = 'application/vnd.oasis.opendocument.graphics-template' 54 | ODF_CHART = 'application/vnd.oasis.opendocument.chart' 55 | ODF_CHART_TEMPLATE = 'application/vnd.oasis.opendocument.chart-template' 56 | ODF_IMAGE = 'application/vnd.oasis.opendocument.image' 57 | ODF_IMAGE_TEMPLATE = 'application/vnd.oasis.opendocument.image-template' 58 | ODF_FORMULA = 'application/vnd.oasis.opendocument.formula' 59 | ODF_FORMULA_TEMPLATE = 'application/vnd.oasis.opendocument.formula-template' 60 | ODF_MASTER = 'application/vnd.oasis.opendocument.text-master' 61 | ODF_WEB = 'application/vnd.oasis.opendocument.text-web' 62 | 63 | 64 | # File extensions and their mimetype 65 | ODF_EXTENSIONS = { 66 | 'odt': ODF_TEXT, 67 | 'ott': ODF_TEXT_TEMPLATE, 68 | 'ods': ODF_SPREADSHEET, 69 | 'ots': ODF_SPREADSHEET_TEMPLATE, 70 | 'odp': ODF_PRESENTATION, 71 | 'otp': ODF_PRESENTATION_TEMPLATE, 72 | 'odg': ODF_DRAWING, 73 | 'otg': ODF_DRAWING_TEMPLATE, 74 | 'odc': ODF_CHART, 75 | 'otc': ODF_CHART_TEMPLATE, 76 | 'odi': ODF_IMAGE, 77 | 'oti': ODF_IMAGE_TEMPLATE, 78 | 'odf': ODF_FORMULA, 79 | 'otf': ODF_FORMULA_TEMPLATE, 80 | 'odm': ODF_MASTER, 81 | 'oth': ODF_WEB, 82 | } 83 | 84 | 85 | # Mimetypes and their file extension 86 | ODF_MIMETYPES = { 87 | ODF_TEXT: 'odt', 88 | ODF_TEXT_TEMPLATE: 'ott', 89 | ODF_SPREADSHEET: 'ods', 90 | ODF_SPREADSHEET_TEMPLATE: 'ots', 91 | ODF_PRESENTATION: 'odp', 92 | ODF_PRESENTATION_TEMPLATE: 'otp', 93 | ODF_DRAWING: 'odg', 94 | ODF_DRAWING_TEMPLATE: 'otg', 95 | ODF_CHART: 'odc', 96 | ODF_CHART_TEMPLATE: 'otc', 97 | ODF_IMAGE: 'odi', 98 | ODF_IMAGE_TEMPLATE: 'oti', 99 | ODF_FORMULA: 'odf', 100 | ODF_FORMULA_TEMPLATE: 'otf', 101 | ODF_MASTER: 'odm', 102 | ODF_WEB: 'oth', 103 | } 104 | 105 | 106 | # Standard parts in the container (other are regular paths) 107 | ODF_PARTS = ('content', 'meta', 'settings', 'styles') 108 | 109 | 110 | # Paths of standard parts 111 | ODF_CONTENT = 'content.xml' 112 | ODF_META = 'meta.xml' 113 | ODF_SETTINGS = 'settings.xml' 114 | ODF_STYLES = 'styles.xml' 115 | ODF_MANIFEST = 'META-INF/manifest.xml' 116 | 117 | 118 | # Presentation classes (for layout) 119 | ODF_CLASSES = ('title', 'outline', 'subtitle', 'text', 'graphic', 'object', 120 | 'chart', 'table', 'orgchart', 'page', 'notes', 'handout') 121 | -------------------------------------------------------------------------------- /scripts/lpod-highlight.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 5 | # 6 | # Authors: Hervé Cauwelier 7 | # 8 | # This file is part of Lpod (see: http://lpod-project.net). 9 | # Lpod is free software; you can redistribute it and/or modify it under 10 | # the terms of either: 11 | # 12 | # a) the GNU General Public License as published by the Free Software 13 | # Foundation, either version 3 of the License, or (at your option) 14 | # any later version. 15 | # Lpod is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # You should have received a copy of the GNU General Public License 20 | # along with Lpod. If not, see . 21 | # 22 | # b) the Apache License, Version 2.0 (the "License"); 23 | # you may not use this file except in compliance with the License. 24 | # You may obtain a copy of the License at 25 | # http://www.apache.org/licenses/LICENSE-2.0 26 | # 27 | 28 | # Import from the standard library 29 | from optparse import OptionParser 30 | from sys import exit, stdin 31 | 32 | # Import from lpod 33 | from lpod import __version__ 34 | from lpod.document import odf_get_document 35 | from lpod.scriptutils import add_option_output, printinfo 36 | from lpod.style import odf_create_style, rgb2hex 37 | 38 | 39 | def highlight(odf_file_url, pattern, color=None, background_color=None, 40 | italic=False, bold=False, target=None, pretty=True): 41 | 42 | # Make display_name and name 43 | display_name = [u"Highlight"] 44 | if color and color != 'none': 45 | display_name.append(unicode(color).capitalize()) 46 | if background_color and background_color != 'none': 47 | display_name.append(unicode(background_color).capitalize()) 48 | if italic: 49 | display_name.append(u"Italic") 50 | if bold: 51 | display_name.append(u"Bold") 52 | display_name = u" ".join(display_name) 53 | name = display_name.replace(u" ", u"_20_") 54 | 55 | # Is our style already installed? 56 | style = document.get_style('text', name) 57 | if style is None: 58 | color = rgb2hex(color) if color != 'none' else None 59 | background_color = (rgb2hex(background_color) 60 | if background_color != 'none' else None) 61 | style = odf_create_style('text', name, 62 | italic=italic, bold=bold, color=color, 63 | background_color=background_color) 64 | document.insert_style(style, automatic=True) 65 | 66 | # Patch! 67 | body = document.get_body() 68 | i = -1 69 | for i, paragraph in enumerate(body.get_paragraphs(content=pattern) + 70 | body.get_headings(content=pattern)): 71 | # Don't colour the table of content 72 | if paragraph.get_parent().get_tag() in ('text:index-title', 73 | 'text:index-body'): 74 | continue 75 | paragraph.set_span(name, regex=pattern) 76 | document.save(target=target, pretty=pretty) 77 | printinfo(str((i + 1)), "paragraphs changed (0 error, 0 warning).") 78 | 79 | 80 | 81 | if __name__ == '__main__': 82 | 83 | # Options initialisation 84 | usage = '%prog ' 85 | description = ("highlight the text matching the given regular " 86 | "expression (Python syntax). May not display in some " 87 | "office suites.") 88 | parser = OptionParser(usage, version=__version__, 89 | description=description) 90 | # --color 91 | help = ("the name or #rrggbb color of the font color: black, blue, " 92 | "brown, cyan, green, grey, magenta, orange, pink, red, violet, " 93 | "white, yellow or none (default)") 94 | parser.add_option('-c', '--color', default='none', metavar='COLOR', 95 | help=help) 96 | # --background 97 | help = ("the name or #rrggbb color of the background color: black, " 98 | "blue, brown, cyan, green, grey, magenta, orange, pink, red, " 99 | "violet, white, yellow (default) or none") 100 | parser.add_option('-g', '--background', default='yellow', 101 | metavar='BACKGROUND', help=help) 102 | # --italic 103 | parser.add_option('-i', '--italic', dest='italic', action='store_true', 104 | default=False, help='set the italic font style') 105 | # --bold 106 | parser.add_option('-b', '--bold', dest='bold', action='store_true', 107 | default=False, help='set the bold font weight') 108 | # --output 109 | add_option_output(parser) 110 | # Parse options 111 | options, args = parser.parse_args() 112 | if len(args) != 2: 113 | parser.print_help() 114 | exit(1) 115 | odf_file_url, pattern = args 116 | pattern = unicode(pattern, stdin.encoding) 117 | document = odf_get_document(odf_file_url) 118 | highlight(document, pattern, options.color, options.background, 119 | options.italic, options.bold, target=options.output) 120 | -------------------------------------------------------------------------------- /test/test_datatype.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | # 3 | # Copyright (c) 2009-2010 Ars Aperta, Itaapy, Pierlis, Talend. 4 | # 5 | # Authors: Hervé Cauwelier 6 | # 7 | # This file is part of Lpod (see: http://lpod-project.net). 8 | # Lpod is free software; you can redistribute it and/or modify it under 9 | # the terms of either: 10 | # 11 | # a) the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) 13 | # any later version. 14 | # Lpod is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # You should have received a copy of the GNU General Public License 19 | # along with Lpod. If not, see . 20 | # 21 | # b) the Apache License, Version 2.0 (the "License"); 22 | # you may not use this file except in compliance with the License. 23 | # You may obtain a copy of the License at 24 | # http://www.apache.org/licenses/LICENSE-2.0 25 | # 26 | 27 | # Import from the Standard Library 28 | from datetime import datetime, timedelta 29 | from decimal import Decimal 30 | from unittest import TestCase, main 31 | 32 | # Import from lpod 33 | from lpod.datatype import DateTime, Duration, Boolean, Unit 34 | 35 | 36 | class DateTimeTestCase(TestCase): 37 | 38 | def test_encode(self): 39 | date = datetime(2009, 06, 26, 11, 9, 36) 40 | expected = '2009-06-26T11:09:36' 41 | self.assertEqual(DateTime.encode(date), expected) 42 | 43 | 44 | def test_decode(self): 45 | date = '2009-06-29T14:33:21' 46 | expected = datetime(2009, 6, 29, 14, 33, 21) 47 | self.assertEqual(DateTime.decode(date), expected) 48 | 49 | 50 | 51 | class DurationTestCase(TestCase): 52 | 53 | def test_encode(self): 54 | duration = timedelta(0, 53, 0, 0, 6) 55 | expected = 'PT00H06M53S' 56 | self.assertEqual(Duration.encode(duration), expected) 57 | 58 | 59 | def test_decode(self): 60 | duration = 'PT12H34M56S' 61 | expected = timedelta(0, 56, 0, 0, 34, 12) 62 | self.assertEqual(Duration.decode(duration), expected) 63 | 64 | 65 | 66 | class BooleanTestCase(TestCase): 67 | 68 | def test_encode(self): 69 | self.assertEqual(Boolean.encode(True), 'true') 70 | self.assertEqual(Boolean.encode(False), 'false') 71 | self.assertEqual(Boolean.encode("true"), 'true') 72 | self.assertEqual(Boolean.encode("false"), 'false') 73 | 74 | 75 | def test_bad_encode(self): 76 | self.assertRaises(TypeError, Boolean.encode, 'on') 77 | self.assertRaises(TypeError, Boolean.encode, 1) 78 | 79 | 80 | def test_decode(self): 81 | self.assertEqual(Boolean.decode('true'), True) 82 | self.assertEqual(Boolean.decode('false'), False) 83 | 84 | 85 | def test_bad_decode(self): 86 | self.assertRaises(ValueError, Boolean.decode, 'True') 87 | self.assertRaises(ValueError, Boolean.decode, '1') 88 | 89 | 90 | 91 | class UnitTestCase(TestCase): 92 | 93 | def test_str(self): 94 | unit = Unit('1.847mm') 95 | self.assertEqual(unit.value, Decimal('1.847')) 96 | self.assertEqual(unit.unit, 'mm') 97 | 98 | 99 | def test_int(self): 100 | unit = Unit(1) 101 | self.assertEqual(unit.value, Decimal('1')) 102 | self.assertEqual(unit.unit, 'cm') 103 | 104 | 105 | def test_float(self): 106 | unit = Unit(3.14) 107 | self.assertEqual(unit.value, Decimal('3.14')) 108 | self.assertEqual(unit.unit, 'cm') 109 | 110 | 111 | def test_encode(self): 112 | value = '1.847mm' 113 | unit = Unit(value) 114 | self.assertEqual(str(unit), value) 115 | 116 | 117 | # TODO use other units once conversion implemented 118 | 119 | def test_eq(self): 120 | unit1 = Unit('2.54cm') 121 | unit2 = Unit('2.54cm') 122 | self.assertTrue(unit1 == unit2) 123 | 124 | 125 | def test_lt(self): 126 | unit1 = Unit('2.53cm') 127 | unit2 = Unit('2.54cm') 128 | self.assertTrue(unit1 < unit2) 129 | 130 | 131 | def test_nlt(self): 132 | unit1 = Unit('2.53cm') 133 | unit2 = Unit('2.54cm') 134 | self.assertFalse(unit1 > unit2) 135 | 136 | 137 | def test_gt(self): 138 | unit1 = Unit('2.54cm') 139 | unit2 = Unit('2.53cm') 140 | self.assertTrue(unit1 > unit2) 141 | 142 | 143 | def test_ngt(self): 144 | unit1 = Unit('2.54cm') 145 | unit2 = Unit('2.53cm') 146 | self.assertFalse(unit1 < unit2) 147 | 148 | 149 | def test_le(self): 150 | unit1 = Unit('2.54cm') 151 | unit2 = Unit('2.54cm') 152 | self.assertTrue(unit1 <= unit2) 153 | 154 | 155 | def test_ge(self): 156 | unit1 = Unit('2.54cm') 157 | unit2 = Unit('2.54cm') 158 | self.assertTrue(unit1 >= unit2) 159 | 160 | 161 | def test_convert(self): 162 | unit = Unit('10cm') 163 | self.assertEqual(unit.convert('px'), Unit('283px')) 164 | 165 | 166 | 167 | if __name__ == '__main__': 168 | main() 169 | --------------------------------------------------------------------------------