sphinx-docx 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sphinx_docx/__init__.py +59 -0
- sphinx_docx/builder.py +180 -0
- sphinx_docx/docx/LICENSE.python-docx +22 -0
- sphinx_docx/docx/__init__.py +1 -0
- sphinx_docx/docx/docx.py +2910 -0
- sphinx_docx/docx/style.docx +0 -0
- sphinx_docx/highlight.py +255 -0
- sphinx_docx/writer.py +3708 -0
- sphinx_docx-1.0.0.dist-info/METADATA +290 -0
- sphinx_docx-1.0.0.dist-info/RECORD +14 -0
- sphinx_docx-1.0.0.dist-info/WHEEL +5 -0
- sphinx_docx-1.0.0.dist-info/licenses/LICENSE +11 -0
- sphinx_docx-1.0.0.dist-info/licenses/sphinx_docx/docx/LICENSE.python-docx +22 -0
- sphinx_docx-1.0.0.dist-info/top_level.txt +1 -0
sphinx_docx/__init__.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Sphinx extension that builds Word (.docx) documents."""
|
|
2
|
+
from importlib.metadata import PackageNotFoundError, version as _version
|
|
3
|
+
|
|
4
|
+
from sphinx.util.osutil import make_filename
|
|
5
|
+
from sphinx_docx.builder import DocxBuilder
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = _version('sphinx-docx')
|
|
9
|
+
except PackageNotFoundError: # running from a source tree, not installed
|
|
10
|
+
__version__ = '0.0.0.dev0'
|
|
11
|
+
|
|
12
|
+
__all__ = ['DocxBuilder', 'setup', '__version__']
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def setup(app):
|
|
16
|
+
"""Register the docx builder and its configuration values with Sphinx."""
|
|
17
|
+
app.add_builder(DocxBuilder)
|
|
18
|
+
|
|
19
|
+
def default_docx_documents(conf):
|
|
20
|
+
"""Build the default ``docx_documents`` entry: one file from the master doc."""
|
|
21
|
+
start_doc = conf.master_doc
|
|
22
|
+
filename = '%s.docx' % make_filename(conf.project)
|
|
23
|
+
title = conf.project
|
|
24
|
+
# author configuration value is available from Sphinx 1.8
|
|
25
|
+
author = getattr(conf, 'author', 'sphinx_docx')
|
|
26
|
+
properties = {
|
|
27
|
+
'title': title,
|
|
28
|
+
'creator': author,
|
|
29
|
+
'subject': '',
|
|
30
|
+
'category': '',
|
|
31
|
+
'description': 'This document generated by sphinx_docx',
|
|
32
|
+
'keywords': ['python', 'Office Open XML', 'Word'],
|
|
33
|
+
}
|
|
34
|
+
toc_only = False
|
|
35
|
+
return [(start_doc, filename, properties, toc_only)]
|
|
36
|
+
|
|
37
|
+
app.add_config_value('docx_documents', default_docx_documents, 'env')
|
|
38
|
+
app.add_config_value('docx_style', '', 'env')
|
|
39
|
+
app.add_config_value('docx_pagebreak_before_section', 0, 'env')
|
|
40
|
+
app.add_config_value('docx_pagebreak_before_file', 0, 'env')
|
|
41
|
+
app.add_config_value('docx_pagebreak_before_table_of_contents', -1, 'env')
|
|
42
|
+
app.add_config_value('docx_pagebreak_after_table_of_contents', 0, 'env')
|
|
43
|
+
app.add_config_value('docx_coverpage', 1, 'env')
|
|
44
|
+
app.add_config_value('docx_update_fields', False, 'env')
|
|
45
|
+
app.add_config_value('docx_bake_property_fields', True, 'env')
|
|
46
|
+
app.add_config_value('docx_table_options', {
|
|
47
|
+
'landscape_columns': 0,
|
|
48
|
+
'in_single_page': False,
|
|
49
|
+
'row_splittable': True,
|
|
50
|
+
'header_in_all_page': False,
|
|
51
|
+
}, 'env')
|
|
52
|
+
app.add_config_value('docx_style_names', {}, 'env')
|
|
53
|
+
app.add_config_value('docx_nested_character_style', True, 'env')
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
'version': __version__,
|
|
57
|
+
'parallel_read_safe': True,
|
|
58
|
+
'parallel_write_safe': True,
|
|
59
|
+
}
|
sphinx_docx/builder.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
sphinxcontrib-docxbuilder
|
|
4
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
5
|
+
|
|
6
|
+
OpenXML Document Sphinx builder.
|
|
7
|
+
|
|
8
|
+
:copyright:
|
|
9
|
+
Copyright 2010 by shimizukawa at gmail dot com (Sphinx-users.jp).
|
|
10
|
+
:license: BSD, see LICENSE for details.
|
|
11
|
+
:modified:
|
|
12
|
+
Modifications for sphinx_docx by Nefti-sama
|
|
13
|
+
https://github.com/Nefti-sama/sphinx_docx
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from docutils import nodes
|
|
19
|
+
from docutils.io import FileOutput
|
|
20
|
+
from sphinx import addnodes
|
|
21
|
+
from sphinx.builders import Builder
|
|
22
|
+
from sphinx.util import logging
|
|
23
|
+
from sphinx.util.docutils import new_document
|
|
24
|
+
from sphinx.util.osutil import ensuredir
|
|
25
|
+
|
|
26
|
+
from sphinx_docx.writer import DocxWriter, DocxTranslator, findall
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DocxBuilder(Builder):
|
|
30
|
+
"""Sphinx builder writing the documentation as docx files."""
|
|
31
|
+
# pylint: disable=attribute-defined-outside-init
|
|
32
|
+
name = 'docx'
|
|
33
|
+
format = 'docx'
|
|
34
|
+
out_suffix = '.docx'
|
|
35
|
+
default_translator_class = DocxTranslator
|
|
36
|
+
|
|
37
|
+
def init(self):
|
|
38
|
+
"""Set up the image directory, logger and document list."""
|
|
39
|
+
self.imagedir = '_images'
|
|
40
|
+
self._logger = logging.getLogger('sphinx_docx')
|
|
41
|
+
self._docx_documents = []
|
|
42
|
+
|
|
43
|
+
def get_outdated_docs(self):
|
|
44
|
+
"""Report outdated documents; every build writes all documents."""
|
|
45
|
+
return 'pass'
|
|
46
|
+
|
|
47
|
+
def get_target_uri(self, docname, typ=None):
|
|
48
|
+
"""Return the target URI of a document, which is its name."""
|
|
49
|
+
return docname
|
|
50
|
+
|
|
51
|
+
def prepare_writing(self, docnames):
|
|
52
|
+
"""Drop invalid ``docx_documents`` entries and create the writer.
|
|
53
|
+
|
|
54
|
+
Entries naming an unknown document or an empty filename are warned about
|
|
55
|
+
and skipped.
|
|
56
|
+
"""
|
|
57
|
+
for entry in self.config.docx_documents:
|
|
58
|
+
if entry[0] not in self.env.all_docs:
|
|
59
|
+
self._logger.warning(
|
|
60
|
+
'unknown document %s is found '
|
|
61
|
+
'in docx_documents' % entry[0])
|
|
62
|
+
continue
|
|
63
|
+
if not entry[1]:
|
|
64
|
+
self._logger.warning(
|
|
65
|
+
'invalid filename %s s found for %s '
|
|
66
|
+
'in docx_documents' % (entry[1]. entry[0]))
|
|
67
|
+
continue
|
|
68
|
+
self._docx_documents.append(entry)
|
|
69
|
+
if not self._docx_documents:
|
|
70
|
+
self._logger.warning('no valid entry is found in docx_documents')
|
|
71
|
+
self.writer = DocxWriter(self)
|
|
72
|
+
|
|
73
|
+
def assemble_doctree(self, master, toctree_only):
|
|
74
|
+
"""Return the doctree of ``master`` with every toctree expanded in place.
|
|
75
|
+
|
|
76
|
+
With ``toctree_only``, only the toctrees of the master document are kept,
|
|
77
|
+
not its own content.
|
|
78
|
+
"""
|
|
79
|
+
tree = self.env.get_doctree(master)
|
|
80
|
+
if toctree_only:
|
|
81
|
+
doc = new_document('sphinx_docx/builder.py')
|
|
82
|
+
for toctree in findall(tree, addnodes.toctree):
|
|
83
|
+
# ids is not assigned to toctree, but to the parent
|
|
84
|
+
toctree.get('ids').extend(toctree.parent.get('ids'))
|
|
85
|
+
doc.append(toctree)
|
|
86
|
+
tree = doc
|
|
87
|
+
tree = insert_all_toctrees(tree, master, self.env, [])
|
|
88
|
+
tree['docname'] = master
|
|
89
|
+
self._logger.info('')
|
|
90
|
+
# TODO: Support cross references
|
|
91
|
+
return tree
|
|
92
|
+
|
|
93
|
+
def make_numfig_map(self):
|
|
94
|
+
"""Map ``docname/node_id`` to a figure number, per figure type."""
|
|
95
|
+
numfig_map = {}
|
|
96
|
+
for docname, item in self.env.toc_fignumbers.items():
|
|
97
|
+
for figtype, info in item.items():
|
|
98
|
+
prefix = self.config.numfig_format.get(figtype)
|
|
99
|
+
if prefix is None:
|
|
100
|
+
continue
|
|
101
|
+
_, num_map = numfig_map.setdefault(figtype, (prefix, {}))
|
|
102
|
+
for node_id, num in info.items():
|
|
103
|
+
key = '%s/%s' % (docname, node_id)
|
|
104
|
+
num_map[key] = num
|
|
105
|
+
return numfig_map
|
|
106
|
+
|
|
107
|
+
def make_numsec_map(self):
|
|
108
|
+
"""Map ``docname/node_id`` to a section number."""
|
|
109
|
+
numsec_map = {}
|
|
110
|
+
for docname, info in self.env.toc_secnumbers.items():
|
|
111
|
+
for node_id, num in info.items():
|
|
112
|
+
key = '%s/%s' % (docname, node_id)
|
|
113
|
+
numsec_map[key] = num
|
|
114
|
+
return numsec_map
|
|
115
|
+
|
|
116
|
+
def write(self, *_ignored): # pylint: disable=arguments-differ
|
|
117
|
+
"""Write every valid ``docx_documents`` entry to a docx file."""
|
|
118
|
+
docnames = self.env.all_docs
|
|
119
|
+
|
|
120
|
+
self._logger.info('preparing documents... ', nonl=True)
|
|
121
|
+
self.prepare_writing(docnames)
|
|
122
|
+
self._logger.info('done')
|
|
123
|
+
|
|
124
|
+
for entry in self._docx_documents:
|
|
125
|
+
start_doc, docname, props = entry[:3]
|
|
126
|
+
toctree_only = entry[3] if len(entry) > 3 else False
|
|
127
|
+
|
|
128
|
+
self._logger.info('processing %s... ' % docname, nonl=True)
|
|
129
|
+
doctree = self.assemble_doctree(start_doc, toctree_only)
|
|
130
|
+
self.doc_properties = props
|
|
131
|
+
self._logger.info('writing... ', nonl=True)
|
|
132
|
+
self.write_doc(docname, doctree)
|
|
133
|
+
self._logger.info('done')
|
|
134
|
+
|
|
135
|
+
def write_doc(self, docname, doctree):
|
|
136
|
+
"""Write one doctree to ``docname`` under the output directory."""
|
|
137
|
+
outfilename = os.path.join(self.outdir, docname)
|
|
138
|
+
ensuredir(os.path.dirname(outfilename))
|
|
139
|
+
# FileOutput handles bytes; BinaryFileOutput is removed in docutils 0.24
|
|
140
|
+
destination = FileOutput(destination_path=outfilename, mode='wb')
|
|
141
|
+
self.writer.write(doctree, destination)
|
|
142
|
+
|
|
143
|
+
def finish(self):
|
|
144
|
+
"""Finish the build; nothing is left to do."""
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
def insert_all_toctrees(tree, docname, env, traversed):
|
|
148
|
+
"""Return a copy of ``tree`` with the documents of each toctree inlined.
|
|
149
|
+
|
|
150
|
+
``traversed`` collects the documents already inlined, so a document
|
|
151
|
+
included twice is expanded only once.
|
|
152
|
+
"""
|
|
153
|
+
tree = tree.deepcopy()
|
|
154
|
+
env.apply_post_transforms(tree, docname)
|
|
155
|
+
for index, toctreenode in enumerate(findall(tree, addnodes.toctree)):
|
|
156
|
+
# Numbered within the document rather than taken from
|
|
157
|
+
# id(toctreenode): that is the object's address, so it differs
|
|
158
|
+
# between runs, and it reaches the file as a bookmark name. Two
|
|
159
|
+
# builds of unchanged sources have to produce the same document.
|
|
160
|
+
nodeid = 'docx_expanded_toctree_%s_%d' % (
|
|
161
|
+
docname.replace('/', '_'), index)
|
|
162
|
+
newnodes = nodes.container(ids=[nodeid])
|
|
163
|
+
toctreenode['docx_expanded_toctree_refid'] = nodeid
|
|
164
|
+
includefiles = toctreenode['includefiles']
|
|
165
|
+
for includefile in includefiles:
|
|
166
|
+
if includefile in traversed:
|
|
167
|
+
continue
|
|
168
|
+
try:
|
|
169
|
+
traversed.append(includefile)
|
|
170
|
+
subtree = insert_all_toctrees(
|
|
171
|
+
env.get_doctree(includefile), includefile, env, traversed)
|
|
172
|
+
except Exception: # pylint: disable=broad-except
|
|
173
|
+
continue
|
|
174
|
+
start_of_file = addnodes.start_of_file(docname=includefile)
|
|
175
|
+
start_of_file.children = subtree.children
|
|
176
|
+
newnodes.append(start_of_file)
|
|
177
|
+
parent = toctreenode.parent
|
|
178
|
+
index = parent.index(toctreenode)
|
|
179
|
+
parent.insert(index + 1, newnodes)
|
|
180
|
+
return tree
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2009-2010 Mike MacCana
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
|
4
|
+
obtaining a copy of this software and associated documentation
|
|
5
|
+
files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use,
|
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the
|
|
9
|
+
Software is furnished to do so, subject to the following
|
|
10
|
+
conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be
|
|
13
|
+
included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from sphinx_docx.docx.docx import *
|