Compare commits

..

No commits in common. "master" and "B1oko-master" have entirely different histories.

9 changed files with 955 additions and 770 deletions

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.9', '3.10', '3.11','3.12','3.13']
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
@ -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

View File

@ -1,7 +1,3 @@
0.20.2 *(Unreleased)*
-------------------
- 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)

View File

@ -286,8 +286,6 @@ 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`.

View File

@ -4,15 +4,11 @@ Created : 2015-03-12
@author: Eric Lapouyade
"""
__version__ = "0.20.1"
# flake8: noqa
from .inline_image import InlineImage
from .listing import Listing
from .richtext import RichText, R, RichTextParagraph, RP
from .subdoc import Subdoc
from .template import DocxTemplate
try:
from .subdoc import Subdoc
except ImportError:
pass

View File

@ -6,7 +6,8 @@ Created : 2015-03-12
"""
from os import PathLike
from typing import TYPE_CHECKING, Any, Optional, IO, Union, Dict, Set
from typing import Any, Optional, IO, Union, Dict, Set
from .subdoc import Subdoc
import functools
import io
from lxml import etree
@ -28,9 +29,6 @@ import binascii
import os
import zipfile
if TYPE_CHECKING:
from .subdoc import Subdoc
class DocxTemplate(object):
"""Class for managing docx files as they were jinja2 templates"""
@ -612,9 +610,7 @@ class DocxTemplate(object):
self.docx_ids_index += 1
elt.attrib["id"] = str(self.docx_ids_index)
def new_subdoc(self, docpath=None) -> Subdoc:
from .subdoc import Subdoc
def new_subdoc(self, docpath=None):
self.init_docx()
return Subdoc(self, docpath)
@ -891,36 +887,34 @@ class DocxTemplate(object):
self.is_saved = True
def get_undeclared_template_variables(
self,
jinja_env: Optional[Environment] = None,
context: Optional[Dict[str, Any]] = None,
self, jinja_env: Optional[Environment] = None, context: Optional[Dict[str, Any]] = None
) -> Set[str]:
# Create a temporary document to analyze the template without affecting the current state
temp_doc = Document(self.template_file)
# Get XML from the temporary document
xml = self.xml_to_string(temp_doc._element.body)
xml = self.patch_xml(xml)
# Add headers and footers
for uri in [self.HEADER_URI, self.FOOTER_URI]:
for relKey, val in temp_doc._part.rels.items():
if (val.reltype == uri) and (val.target_part.blob):
_xml = self.xml_to_string(parse_xml(val.target_part.blob))
xml += self.patch_xml(_xml)
if jinja_env:
env = jinja_env
else:
env = Environment()
parse_content = env.parse(xml)
all_variables = meta.find_undeclared_variables(parse_content)
# If context is provided, return only variables that are not in the context
if context is not None:
provided_variables = set(context.keys())
return all_variables - provided_variables
# If no context provided, return all variables (original behavior)
return all_variables
return all_variables

1587
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +1,22 @@
[project]
name = "docxtpl"
dynamic = ["version"]
description = "Python docx template engine"
authors = [{name="Eric Lapouyade", email="elapouya@proton.me"}]
readme = "README.rst"
requires-python = ">=3.7"
license = {text="LGPL-2.1-only"}
classifiers=[
"Intended Audience :: Developers",
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
keywords = ["jinja2"]
dependencies = [
"python-docx",
"jinja2",
"lxml",
]
[project.optional-dependencies]
subdoc = ["docxcompose"]
docs = ["Sphinx", "sphinxcontrib-napoleon"]
[dependency-groups]
dev = [
"mypy >=1.18.2; python_version >= '3.9'",
"lxml-stubs >=0.5.1; python_version >= '3.9'",
"flake8 >=7.3.0; python_version >= '3.9'"
]
[project.urls]
homepage = "https://github.com/elapouya/python-docx-template"
repository = "https://github.com/elapouya/python-docx-template.git"
document = "https://docxtpl.readthedocs.org"
[tool.poetry]
version = "0.0.0"
name = "docxtpl"
version = "0.17.0"
description = "Python docx template engine"
authors = ["Eric Lapouyade"]
readme = "README.rst"
[tool.poetry.requires-plugins]
poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] }
[tool.poetry.dependencies]
python = "^3.11"
python-docx = "^1.1.2"
docxcompose = "^1.4.0"
jinja2 = "^3.1.4"
black = "^24.4.2"
twine = "^6.1.0"
[tool.poetry-dynamic-versioning]
enable = true
[tool.poetry-dynamic-versioning.from-file]
source = "docxtpl/__init__.py"
pattern = '__version__ = "(.+)"'
[tool.mypy]
pretty = true
python_version = "3.9"
check_untyped_defs = true
warn_unused_ignores = true
exclude = ["docs", "build", "setup.py"]
[[tool.mypy.overrides]]
module = ["docxcompose.*"]
ignore_missing_imports = true
[tool.poetry.group.dev.dependencies]
flake8 = "^7.1.0"
[build-system]
requires = ["poetry-core", "poetry-dynamic-versioning >=1.0.0,<2.0.0"]
build-backend = "poetry_dynamic_versioning.backend"
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[bdist_wheel]
universal = 1

View File

@ -1,9 +1,8 @@
from setuptools import setup
import os
import re
import sys
from setuptools import setup
# To register onto Pypi :
# python setup.py sdist bdist_wheel upload
@ -51,7 +50,6 @@ setup(
version=get_version("docxtpl"),
description="Python docx template engine",
long_description=long_description,
long_description_content_type="text/x-rst",
classifiers=[
"Intended Audience :: Developers",
"Development Status :: 4 - Beta",
@ -62,16 +60,14 @@ setup(
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
],
keywords="jinja2",
url="https://github.com/elapouya/python-docx-template",
author="Eric Lapouyade",
license="LGPL-2.1-only",
license_files=[],
license="LGPL 2.1",
packages=["docxtpl"],
install_requires=["python-docx>=1.1.1", "jinja2", "lxml"],
extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"], "subdoc": ["docxcompose"]},
install_requires=["python-docx>=1.1.1", "docxcompose", "jinja2", "lxml"],
extras_require={"docs": ["Sphinx", "sphinxcontrib-napoleon"]},
eager_resources=["docs"],
zip_safe=False,
)