Skip to content

Commit f548b6e

Browse files
committed
Merge branch 'type-hints' into feat-uv-pdm
2 parents 346ffa5 + b40de05 commit f548b6e

14 files changed

Lines changed: 809 additions & 14 deletions

.github/workflows/codestyle.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,39 @@ jobs:
99
matrix:
1010
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
1111
steps:
12+
<<<<<<< HEAD
1213
- uses: actions/checkout@v4
1314
- name: Set up Python ${{ matrix.python-version }}
1415
uses: actions/setup-python@v5
1516
with:
1617
python-version: ${{ matrix.python-version }}
1718
allow-prereleases: true
1819
- uses: astral-sh/setup-uv@v6
20+
=======
21+
- uses: actions/checkout@v5
22+
- name: Set up Python ${{ matrix.python-version }}
23+
uses: actions/setup-python@v6
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
allow-prereleases: true
27+
>>>>>>> type-hints
1928
- name: Install dependencies
2029
run: uv sync --all-extras --all-groups
2130
- name: Lint with flake8
2231
run: |
2332
# stop the build if there are code styling problems. The GitHub editor is 127 chars wide.
33+
<<<<<<< HEAD
2434
uv run flake8 . --count --max-line-length=127 --show-source --statistics --exclude .venv,__pycache__
2535
- name: Check type hints
2636
run: uv run mypy .
37+
=======
38+
flake8 . --count --max-line-length=127 --show-source --statistics
39+
- name: Check type hints
40+
run: |
41+
pip install mypy lxml-stubs
42+
mypy .
43+
- name: Ensure library work without docxcompose
44+
run: |
45+
pip uninstall -y docxcompose
46+
python -c "from docxtpl import *"
47+
>>>>>>> type-hints

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,10 @@ target/
6363

6464
#Pycharm
6565
.idea
66+
<<<<<<< HEAD
6667
.pdm-python
68+
=======
69+
70+
# In Project Virtual Environment
71+
.venv/
72+
>>>>>>> type-hints

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
0.20.2 *(Unreleased)*
2+
-------------------
3+
- Move docxcompose to optional dependency (Thanks to Waket Zheng)
4+
15
0.20.1 (2025-07-15)
26
-------------------
37
- Fix and improve get_undeclared_template_variables() method (Thanks to Pablo Esteban)

docxtpl/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@
1212
from .listing import Listing
1313
from .richtext import RichText, R, RichTextParagraph, RP
1414
from .template import DocxTemplate
15+
try:
16+
from .subdoc import Subdoc
17+
except ImportError:
18+
pass

docxtpl/__main__.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import argparse
24
import json
35
import os
@@ -11,7 +13,7 @@
1113
QUIET_ARG = "quiet"
1214

1315

14-
def make_arg_parser():
16+
def make_arg_parser() -> argparse.ArgumentParser:
1517
parser = argparse.ArgumentParser(
1618
usage="python -m docxtpl [-h] [-o] [-q] {} {} {}".format(
1719
TEMPLATE_ARG, JSON_ARG, OUTPUT_ARG
@@ -42,7 +44,7 @@ def make_arg_parser():
4244
return parser
4345

4446

45-
def get_args(parser):
47+
def get_args(parser) -> dict:
4648
try:
4749
parsed_args = vars(parser.parse_args())
4850
return parsed_args
@@ -57,7 +59,7 @@ def get_args(parser):
5759
)
5860

5961

60-
def is_argument_valid(arg_name, arg_value, overwrite):
62+
def is_argument_valid(arg_name: str, arg_value: str, overwrite: bool) -> bool | None:
6163
# Basic checks for the arguments
6264
if arg_name == TEMPLATE_ARG:
6365
return os.path.isfile(arg_value) and arg_value.endswith(".docx")
@@ -69,9 +71,10 @@ def is_argument_valid(arg_name, arg_value, overwrite):
6971
)
7072
elif arg_name in [OVERWRITE_ARG, QUIET_ARG]:
7173
return arg_value in [True, False]
74+
return None
7275

7376

74-
def check_exists_ask_overwrite(arg_value, overwrite):
77+
def check_exists_ask_overwrite(arg_value: str, overwrite: bool) -> bool:
7578
# If output file does not exist or command was run with overwrite option,
7679
# returns True, else asks for overwrite confirmation. If overwrite is
7780
# confirmed returns True, else raises OSError.
@@ -93,7 +96,7 @@ def check_exists_ask_overwrite(arg_value, overwrite):
9396
return True
9497

9598

96-
def validate_all_args(parsed_args):
99+
def validate_all_args(parsed_args: dict) -> None:
97100
overwrite = parsed_args[OVERWRITE_ARG]
98101
# Raises AssertionError if any of the arguments is not validated
99102
try:
@@ -108,7 +111,7 @@ def validate_all_args(parsed_args):
108111
)
109112

110113

111-
def get_json_data(json_path):
114+
def get_json_data(json_path) -> dict:
112115
with open(json_path) as file:
113116
try:
114117
json_data = json.load(file)
@@ -121,22 +124,22 @@ def get_json_data(json_path):
121124
raise RuntimeError("Failed to get json data.")
122125

123126

124-
def make_docxtemplate(template_path):
127+
def make_docxtemplate(template_path: str) -> DocxTemplate:
125128
try:
126129
return DocxTemplate(template_path)
127130
except TemplateError:
128131
raise RuntimeError("Could not create docx template.")
129132

130133

131-
def render_docx(doc, json_data):
134+
def render_docx(doc: DocxTemplate, json_data: dict) -> DocxTemplate:
132135
try:
133136
doc.render(json_data)
134137
return doc
135138
except TemplateError:
136139
raise RuntimeError("An error ocurred while trying to render the docx")
137140

138141

139-
def save_file(doc, parsed_args):
142+
def save_file(doc: DocxTemplate, parsed_args: dict) -> None:
140143
try:
141144
output_path = parsed_args[OUTPUT_ARG]
142145
doc.save(output_path)
@@ -151,7 +154,7 @@ def save_file(doc, parsed_args):
151154
raise RuntimeError("Failed to save file.")
152155

153156

154-
def main():
157+
def main() -> None:
155158
parser = make_arg_parser()
156159
# Everything is in a try-except block that catches a RuntimeError that is
157160
# raised if any of the individual functions called cause an error

docxtpl/_compat.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# -*- coding: utf-8 -*-
2+
try:
3+
from html import escape
4+
except ImportError:
5+
# cgi.escape is deprecated in python 3.7
6+
from cgi import escape # type:ignore[attr-defined,no-redef]
7+
8+
9+
__all__ = ("escape",)

docxtpl/inline_image.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@
77

88
from __future__ import annotations
99

10+
<<<<<<< HEAD
1011
from typing import IO
12+
=======
13+
from typing import IO, TYPE_CHECKING
14+
>>>>>>> type-hints
1115

1216
from docx.oxml import OxmlElement, parse_xml
1317
from docx.oxml.ns import qn
1418
from docx.shared import Length
1519

1620
from .template import DocxTemplate
1721

22+
if TYPE_CHECKING:
23+
from docx.shared import Length
24+
from .template import DocxTemplate
25+
1826

1927
class InlineImage(object):
2028
"""Class to generate an inline image

docxtpl/listing.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
@author: Eric Lapouyade
66
"""
77

8+
<<<<<<< HEAD
89
try:
910
from html import escape
1011
except ImportError:
1112
# cgi.escape is deprecated in python 3.7
1213
from cgi import escape # type:ignore[attr-defined,no-redef]
14+
=======
15+
from ._compat import escape
16+
>>>>>>> type-hints
1317

1418

1519
class Listing(object):

docxtpl/richtext.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
@author: Eric Lapouyade
66
"""
77

8+
<<<<<<< HEAD
89
try:
910
from html import escape
1011
except ImportError:
1112
# cgi.escape is deprecated in python 3.7
1213
from cgi import escape # type:ignore[attr-defined,no-redef]
14+
=======
15+
from ._compat import escape
16+
>>>>>>> type-hints
1317

1418

1519
class RichText(object):

0 commit comments

Comments
 (0)