Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d042d45
Merge branch 'quintagroup-fix/resolve_listing_function'
May 8, 2023
d539119
PR #493
May 8, 2023
d43c6de
Changed README.rst
May 8, 2023
24de22b
regen pipfile.lock with newer jinja2 dependency version
dralexxx Feb 10, 2024
bee0706
Merge pull request #527 from dralexxx/update_jinja2_version
elapouya Feb 12, 2024
58de890
v0.17.0 -> requires python-docx 1.1.1+
May 1, 2024
d322120
Fix CHANGES.rst
May 1, 2024
e0d5eb0
Added hyperlink option in InlineImage
jeanmarcosdarosa Jul 9, 2024
664bb84
Bump setuptools from 69.5.1 to 70.0.0
dependabot[bot] Jul 15, 2024
0642bad
Update index.rst
jkpet Jul 19, 2024
b7872d7
Add poetry env
elapouya Jul 21, 2024
f3ba468
Merge pull request #552 from jeanmarcosdarosa/jeanmarcosdarosa-patch-…
elapouya Jul 21, 2024
a50b52b
PR #552 + black all files
elapouya Jul 21, 2024
ac38610
Code styling
elapouya Jul 21, 2024
ce25ec8
Merge pull request #554 from elapouya/dependabot/pip/setuptools-70.0.0
elapouya Jul 21, 2024
d472308
Merge pull request #555 from jkpet/patch-1
elapouya Jul 21, 2024
a10c3c1
Remove python 2.x support
elapouya Jul 21, 2024
83ecb60
Merge remote-tracking branch 'origin/master'
elapouya Jul 21, 2024
b9be3a5
Update CHANGES.rst
elapouya Jul 21, 2024
d996070
remove leftover "six" reference
a-detiste Jul 30, 2024
0607e71
Merge pull request #556 from a-detiste/master
elapouya Jul 31, 2024
0061b55
[WIP] Support rendering variables in footnotes
bartbroere Sep 17, 2024
2886a85
Change the XML library to lxml to avoid namespace renaming and other …
bartbroere Sep 17, 2024
2812487
Simplify the code
bartbroere Sep 17, 2024
a449f01
Fix flake8
bartbroere Sep 18, 2024
1cca257
Add a test and use existing XML patching method
bartbroere Sep 23, 2024
9124386
Fix flake8
bartbroere Sep 23, 2024
0d616ad
Apply suggestion since part.blob changes type in the loop
bartbroere Oct 24, 2024
0ef74a7
Change to isinstance for type checking
bartbroere Oct 24, 2024
bc92389
Merge branch 'bartbroere-patch-1'
Nov 12, 2024
0f42e5a
v0.19.0
Nov 12, 2024
65e00b1
Flake8 : whitespace fix
Nov 12, 2024
60caff8
Flake8 : whitespace fix
Nov 12, 2024
eed645c
encode XML as bytes in render_footnotes()
jhpyle Nov 29, 2024
def1205
Merge pull request #575 from jhpyle/patch-1
elapouya Dec 29, 2024
b97fa32
v0.19.1
Dec 29, 2024
aa7b7a7
Rich Text Paragraph Formatting Update
ST-Imrie Feb 28, 2025
994da90
fixed rtl italic formatting
bm-rana Apr 3, 2025
97df786
Added possibility to skip missing pictures instead of raising ValueEr…
aperechnev Apr 4, 2025
ebc770a
Updated RichText Jinja tags from rr/rp to r/q and updated test template
ST-Imrie May 1, 2025
08a5d74
Merge pull request #593 from aperechnev/master
elapouya May 2, 2025
6854250
Merge pull request #592 from bm-rana/bold-rtl-fix
elapouya May 2, 2025
a48a6a9
Merge branch 'refs/heads/ST-Imrie-master'
May 2, 2025
9392b06
add RichTextParagraph class
May 2, 2025
4086140
black
May 2, 2025
fb0e358
v0.20.0
May 6, 2025
e766040
Add .readthedocs.yaml
May 6, 2025
b391b21
update sphinx theme
May 6, 2025
4477729
move requirements.txt
May 6, 2025
399761f
Update sphynx conf.py
May 6, 2025
606d189
- The get_undeclared_template_variables method now analyzes the origi…
B1oko Jul 11, 2025
cbbeae5
Fix and improve get_undeclared_template_variables() method
elapouya Jul 15, 2025
416729d
Run black on template.py
elapouya Jul 15, 2025
d9bb19c
Update setup.py
elapouya Jul 15, 2025
7a6ddbc
Move docxcompose to optional dependency
waketzheng Sep 23, 2025
e77cbf8
Fix pip install error with `--editable`
waketzheng Sep 23, 2025
560b4b3
Use poetry-dynamic-versioning instead of pdm
waketzheng Sep 24, 2025
f96b0b6
Merge pull request #617 from waketzheng/project-section
elapouya Sep 24, 2025
fab696c
Fix NameError: name Subdoc is not defined
waketzheng Nov 2, 2025
cf5437b
Merge pull request #623 from waketzheng/fix-subdoc
elapouya Nov 13, 2025
082a1c6
v0.20.2
Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codestyle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -22,4 +22,4 @@ jobs:
run: |
pip install flake8
# stop the build if there are code styling problems. The GitHub editor is 127 chars wide.
flake8 . --count --max-line-length=127 --show-source --statistics
flake8 . --count --max-line-length=127 --show-source --statistics
35 changes: 35 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Read the Docs configuration file for Sphinx projects
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.12"
# You can also specify other tool versions:
# nodejs: "20"
# rust: "1.70"
# golang: "1.20"

# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
# fail_on_warning: true

# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub

# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: requirements.txt
43 changes: 43 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
0.20.2 (2025-11-13)
-------------------
- Fix fix_tables()
- Move docxcompose to optional dependency (Thanks to Waket Zheng)

0.20.1 (2025-07-15)
-------------------
- Fix and improve get_undeclared_template_variables() method (Thanks to Pablo Esteban)

0.20.0 (2024-12-29)
-------------------
- Add RichTextParagraph (Thanks to ST-Imrie)
- Add RTL support for bold/italic (Thanks to bm-rana)
- Update documentation

0.19.1 (2024-12-29)
-------------------
- PR #575 : fix unicode in footnotes (Thanks to Jonathan Pyle)

0.19.0 (2024-11-12)
-------------------
- Support rendering variables in footnotes (Thanks to Bart Broere)

0.18.0 (2024-07-21)
-------------------
- IMPORTANT : Remove Python 2.x support
- Add hyperlink option in InlineImage (Thanks to Jean Marcos da Rosa)
- Update index.rst (Thanks to jkpet)
- Add poetry env
- Black all files

0.17.0 (2024-05-01)
-------------------
- Add support to python-docx 1.1.1

0.16.8 (2024-02-23)
-------------------
- PR #527 : upgrade Jinja2 in Pipfile.lock

0.16.7 (2023-05-08)
-------------------
- PR #493 - thanks to AdrianVorobel

0.16.6 (2023-03-12)
-------------------
- PR #482 - thanks to dreizehnutters
Expand Down
491 changes: 352 additions & 139 deletions Pipfile.lock

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ You save the document as a .docx file (xml format) : it will be your .docx templ

Now you can use python-docx-template to generate as many word documents you want from this .docx template and context variables you will associate.

Share
-----

If you like this project, please rate and share it here : http://rate.re/github/elapouya/python-docx-template

Documentation
-------------
Expand All @@ -34,8 +30,9 @@ Please, `read the doc <http://docxtpl.readthedocs.org>`_
Other projects
--------------

Have a look at some of my other projects :
If you like python-docx-template, please have a look at some of my other projects :

- `django-listing <https://github.com/elapouya/django-listing>`_ : A listing/table library on steroid for Djano
- `python-textops3 <https://github.com/elapouya/python-textops3>`_ : Chainable text operations
- `django-robohash-svg <https://github.com/elapouya/django-robohash-svg>`_ : Create svg robots avatars

56 changes: 36 additions & 20 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,33 @@
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
"sphinx.ext.autodoc",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]

# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"

# The encoding of source files.
# source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'
master_doc = "index"

# General information about the project.
project = u'python-docx-template'
copyright = u'2015, Eric Lapouyade'
project = "python-docx-template"
copyright = "2015, Eric Lapouyade"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.9'
version = "0.20"
# The full version, including alpha/beta/rc tags.
release = '0.9.x'
release = "0.20.x"

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand All @@ -66,7 +66,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]

# The reST default role (used for this markup: `text`) to use for all
# documents.
Expand All @@ -84,7 +84,7 @@
# show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"

# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
Expand All @@ -97,7 +97,7 @@

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = "sphinx_book_theme"

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
Expand Down Expand Up @@ -126,7 +126,7 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]

# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
Expand Down Expand Up @@ -175,7 +175,7 @@
# html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'python-docx-templatedoc'
htmlhelp_basename = "python-docx-templatedoc"


# -- Options for LaTeX output ---------------------------------------------
Expand All @@ -193,8 +193,13 @@
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'python-docx-template.tex', u'python-docx-template Documentation',
u'Eric Lapouyade', 'manual'),
(
"index",
"python-docx-template.tex",
"python-docx-template Documentation",
"Eric Lapouyade",
"manual",
),
]

# The name of an image file (relative to this directory) to place at the top of
Expand Down Expand Up @@ -223,8 +228,13 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'python-docx-template', u'python-docx-template Documentation',
[u'Eric Lapouyade'], 1)
(
"index",
"python-docx-template",
"python-docx-template Documentation",
["Eric Lapouyade"],
1,
)
]

# If true, show URL addresses after external links.
Expand All @@ -237,9 +247,15 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'python-docx-template', u'python-docx-template Documentation',
u'Eric Lapouyade', 'python-docx-template', 'One line description of project.',
'Miscellaneous'),
(
"index",
"python-docx-template",
"python-docx-template Documentation",
"Eric Lapouyade",
"python-docx-template",
"One line description of project.",
"Miscellaneous",
),
]

# Documents to append as an appendix to all manuals.
Expand Down
24 changes: 22 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ You can add an hyperlink to a text by using a Richtext with this syntax::

Put ``rt`` in your context, then use ``{{r rt}}`` in your template

RichTextParagraph
-----------------

If you want to change paragraph properties, you can use ``RichTextParagraph()`` or ``RP()`` object.
It must be added to the template by using ``{{p <var> }}``.
Have a look to the example here ``tests/richtextparagraph.py``.


Inline image
------------

Expand All @@ -278,6 +286,8 @@ Please see tests/inline_image.py for an example.
Sub-documents
-------------

> Need to install with the subdoc extra: `pip install "docxtpl[subdoc]"`

A template variable can contain a complex subdoc object and be built from scratch using python-docx document methods.
To do so, first, get the sub-document object from your template object, then use it by treating it as a python-docx document object.
See example in `tests/subdoc.py`.
Expand All @@ -288,6 +298,16 @@ calling method `new_subdoc()` ::
tpl = DocxTemplate('templates/merge_docx_master_tpl.docx')
sd = tpl.new_subdoc('templates/merge_docx_subdoc.docx')

context = {
'mysubdoc': sd,
}

tpl.render(context)
tpl.save('output/merge_docx.docx')

In the above example, the content of 'templates/merge_docx_subdoc.docx' will be inserted into the parent document in place of the declared
variable `{{p mysubdoc }}`.

See `tests/merge_docx.py` for full code.

.. _Escaping:
Expand Down Expand Up @@ -388,9 +408,9 @@ In order to get the missing variables after rendering use ::

tpl=DocxTemplate('your_template.docx')
tpl.render(context_dict)
set_of_variables = tpl.get_undeclared_template_variables()
set_of_variables = tpl.get_undeclared_template_variables(context=context_dict)

**IMPORTANT** : You may use the method before rendering to get a set of keys you need, e.g. to be prompted to a user or written in a file for manual processing.
**IMPORTANT** : If `context` is not passed, you will get a set with all keys you need, e.g. to be prompted to a user or written in a file for manual processing.

Multiple rendering
------------------
Expand Down
11 changes: 8 additions & 3 deletions docxtpl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@

@author: Eric Lapouyade
"""
__version__ = '0.16.6'

__version__ = "0.20.2"

# flake8: noqa
from .inline_image import InlineImage
from .listing import Listing
from .richtext import RichText, R
from .subdoc import Subdoc
from .richtext import RichText, R, RichTextParagraph, RP
from .template import DocxTemplate

try:
from .subdoc import Subdoc
except ImportError:
pass
Loading