|
1 | 1 | import os |
2 | 2 | from zipfile import ZipFile |
3 | 3 |
|
4 | | -from jinja2 import Environment, FileSystemLoader |
| 4 | +from jinja2 import Environment, PackageLoader |
5 | 5 |
|
6 | 6 | from alinka.constants import DocumentsTypes |
7 | 7 | from alinka.schemas import DocumentData |
8 | 8 |
|
9 | | -TEMPLATES_BASE_PATH = os.path.join(os.path.dirname(__file__), "templates") |
10 | | -loader = FileSystemLoader(TEMPLATES_BASE_PATH) |
| 9 | +# Use PackageLoader so resources are resolved correctly from the installed package |
| 10 | +# (works with Windows installer and PyInstaller) |
| 11 | +loader = PackageLoader("alinka.docx", "templates") |
11 | 12 | environment = Environment(loader=loader) |
12 | 13 |
|
13 | 14 |
|
@@ -41,22 +42,37 @@ def files_path_parts(self): |
41 | 42 | ] |
42 | 43 |
|
43 | 44 | @property |
44 | | - def footnotes_file_path(self): |
45 | | - return os.path.join(TEMPLATES_BASE_PATH, self.document_type, "word", "footnotes.xml") |
| 45 | + def footnotes_template_name(self): |
| 46 | + return "/".join([self.document_type, "word", "footnotes.xml"]) |
46 | 47 |
|
47 | 48 | def get_rendered_document(self): |
48 | 49 | data = self.document_data.model_dump() |
49 | 50 | return self.template.render(data) |
50 | 51 |
|
| 52 | + def _get_resource_bytes(self, template_name: str) -> bytes: |
| 53 | + # Read template content via Jinja loader regardless of filesystem location |
| 54 | + source, _, _ = environment.loader.get_source(environment, template_name) |
| 55 | + return source.encode("utf-8") |
| 56 | + |
51 | 57 | def generate(self): |
52 | 58 | with ZipFile(self.destination_path, "w") as document: |
| 59 | + # Write common static files from the packaged templates |
53 | 60 | for path_parts in self.files_path_parts: |
54 | | - file_arch_path = os.path.join(*path_parts) |
55 | | - file_source_path = os.path.join(TEMPLATES_BASE_PATH, "commons", file_arch_path) |
56 | | - document.write(filename=file_source_path, arcname=file_arch_path) |
57 | | - |
58 | | - document.write(filename=self.footnotes_file_path, arcname=os.path.join("word", "footnotes.xml")) |
59 | | - document.writestr(data=self.get_rendered_document(), zinfo_or_arcname=os.path.join("word", "document.xml")) |
| 61 | + file_arch_path = "/".join(path_parts) # Jinja loader expects forward slashes |
| 62 | + common_template_name = "/".join(["commons", file_arch_path]) |
| 63 | + document.writestr(zinfo_or_arcname=file_arch_path, data=self._get_resource_bytes(common_template_name)) |
| 64 | + |
| 65 | + # Write footnotes file for the specific document type |
| 66 | + document.writestr( |
| 67 | + data=self._get_resource_bytes(self.footnotes_template_name), |
| 68 | + zinfo_or_arcname=os.path.join("word", "footnotes.xml"), |
| 69 | + ) |
| 70 | + |
| 71 | + # Write rendered document.xml |
| 72 | + document.writestr( |
| 73 | + data=self.get_rendered_document(), |
| 74 | + zinfo_or_arcname=os.path.join("word", "document.xml"), |
| 75 | + ) |
60 | 76 |
|
61 | 77 |
|
62 | 78 | class Documents: |
|
0 commit comments