latextify 0.3.2__tar.gz → 0.3.4__tar.gz

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.
Files changed (387) hide show
  1. {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/ci.yml +48 -3
  2. {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/publish.yml +20 -9
  3. {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/release.yml +126 -12
  4. {latextify-0.3.2 → latextify-0.3.4}/PKG-INFO +40 -3
  5. {latextify-0.3.2 → latextify-0.3.4}/README.md +39 -2
  6. latextify-0.3.4/examples/04-combined-emf/README.txt +19 -0
  7. latextify-0.3.4/examples/04-combined-emf/make_sample.py +114 -0
  8. {latextify-0.3.2 → latextify-0.3.4}/examples/README.md +10 -6
  9. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_convert.py +12 -0
  10. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_kit.py +6 -0
  11. latextify-0.3.4/latextify/gui/diagnostics_routes.py +20 -0
  12. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/server.py +2 -0
  13. latextify-0.3.4/latextify/gui/static/diagnostics.js +44 -0
  14. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/index.html +14 -0
  15. latextify-0.3.4/latextify/integrity.py +128 -0
  16. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/README-OFFLINE.md +4 -0
  17. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/build.py +10 -4
  18. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/install_template.py +8 -0
  19. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/target.py +2 -0
  20. {latextify-0.3.2 → latextify-0.3.4}/latextify/portable.py +42 -2
  21. latextify-0.3.4/latextify/system_check.py +143 -0
  22. latextify-0.3.4/packaging/README-WINDOWS-OFFLINE-REPO.txt +67 -0
  23. {latextify-0.3.2 → latextify-0.3.4}/packaging/README-WINDOWS-PORTABLE.txt +11 -0
  24. latextify-0.3.4/packaging/Verify-LaTeXtify-Portable.bat +15 -0
  25. latextify-0.3.4/packaging/Verify-LaTeXtify-Repo.bat +14 -0
  26. latextify-0.3.4/packaging/verify_installation.py +23 -0
  27. {latextify-0.3.2 → latextify-0.3.4}/plans/OFFLINE_DISTRIBUTION_PLAN.md +34 -22
  28. {latextify-0.3.2 → latextify-0.3.4}/pyproject.toml +1 -1
  29. latextify-0.3.4/startup-online.bat +5 -0
  30. {latextify-0.3.2 → latextify-0.3.4}/startup.bat +46 -7
  31. {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli.py +52 -0
  32. {latextify-0.3.2 → latextify-0.3.4}/tests/test_gui.py +26 -0
  33. latextify-0.3.4/tests/test_integrity.py +46 -0
  34. {latextify-0.3.2 → latextify-0.3.4}/tests/test_kit_build.py +28 -0
  35. latextify-0.3.4/tests/test_offline_repo.py +62 -0
  36. latextify-0.3.4/tests/test_system_check.py +38 -0
  37. latextify-0.3.4/tools/build_windows_offline_repo.py +175 -0
  38. {latextify-0.3.2 → latextify-0.3.4}/tools/build_windows_portable.py +21 -0
  39. {latextify-0.3.2 → latextify-0.3.4}/uv.lock +1 -1
  40. {latextify-0.3.2 → latextify-0.3.4}/.dockerignore +0 -0
  41. {latextify-0.3.2 → latextify-0.3.4}/.gitattributes +0 -0
  42. {latextify-0.3.2 → latextify-0.3.4}/.github/dependabot.yml +0 -0
  43. {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/codeql.yml +0 -0
  44. {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/dependency-audit.yml +0 -0
  45. {latextify-0.3.2 → latextify-0.3.4}/.gitignore +0 -0
  46. {latextify-0.3.2 → latextify-0.3.4}/.python-version +0 -0
  47. {latextify-0.3.2 → latextify-0.3.4}/CONTRIBUTING.md +0 -0
  48. {latextify-0.3.2 → latextify-0.3.4}/LICENSE +0 -0
  49. {latextify-0.3.2 → latextify-0.3.4}/NOTICE +0 -0
  50. {latextify-0.3.2 → latextify-0.3.4}/SECURITY.md +0 -0
  51. {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/DEPLOY.md +0 -0
  52. {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/Dockerfile +0 -0
  53. {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/README.md +0 -0
  54. {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/warm_cache.py +0 -0
  55. {latextify-0.3.2 → latextify-0.3.4}/deploy/render/DEPLOY.md +0 -0
  56. {latextify-0.3.2 → latextify-0.3.4}/deploy/render/Dockerfile +0 -0
  57. {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/.gitignore +0 -0
  58. {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/README.md +0 -0
  59. {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/make_manuscript.py +0 -0
  60. {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/run.py +0 -0
  61. {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/.gitignore +0 -0
  62. {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/README.md +0 -0
  63. {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/make_manuscript.py +0 -0
  64. {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/run.py +0 -0
  65. {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/.gitignore +0 -0
  66. {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/README.md +0 -0
  67. {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/make_manuscript.py +0 -0
  68. {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/run.py +0 -0
  69. {latextify-0.3.2 → latextify-0.3.4}/latextify/__init__.py +0 -0
  70. {latextify-0.3.2 → latextify-0.3.4}/latextify/__main__.py +0 -0
  71. {latextify-0.3.2 → latextify-0.3.4}/latextify/audit/__init__.py +0 -0
  72. {latextify-0.3.2 → latextify-0.3.4}/latextify/audit/equations.py +0 -0
  73. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/__init__.py +0 -0
  74. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/authoryear_index.py +0 -0
  75. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bib.py +0 -0
  76. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bibmatch.py +0 -0
  77. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bibtex_in.py +0 -0
  78. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/body_markers.py +0 -0
  79. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/corrections.py +0 -0
  80. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/crossref.py +0 -0
  81. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/csl_json_in.py +0 -0
  82. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/endnote.py +0 -0
  83. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/endnote_xml_in.py +0 -0
  84. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/fields.py +0 -0
  85. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/mendeley.py +0 -0
  86. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/merge.py +0 -0
  87. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/nbib_in.py +0 -0
  88. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/plaintext.py +0 -0
  89. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/reconcile.py +0 -0
  90. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/reflist_nondocx.py +0 -0
  91. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/refs_import.py +0 -0
  92. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/validate.py +0 -0
  93. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/wordnative.py +0 -0
  94. {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/zotero.py +0 -0
  95. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli.py +0 -0
  96. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_batch.py +0 -0
  97. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_equations.py +0 -0
  98. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_export.py +0 -0
  99. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_figures.py +0 -0
  100. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_privacy.py +0 -0
  101. {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_review.py +0 -0
  102. {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/__init__.py +0 -0
  103. {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/logs.py +0 -0
  104. {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/pdf.py +0 -0
  105. {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/tectonic.py +0 -0
  106. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/__init__.py +0 -0
  107. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/alt_formats.py +0 -0
  108. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/alt_formats_render.py +0 -0
  109. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/anchors.py +0 -0
  110. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/bibliography.py +0 -0
  111. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/citation_resolution.py +0 -0
  112. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/figures_copy.py +0 -0
  113. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/figures_stage.py +0 -0
  114. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/inline_supplement.py +0 -0
  115. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/metadata.py +0 -0
  116. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/output_dir.py +0 -0
  117. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/project.py +0 -0
  118. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/submission.py +0 -0
  119. {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/supplement.py +0 -0
  120. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/__init__.py +0 -0
  121. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/caption_gaps.py +0 -0
  122. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/convert.py +0 -0
  123. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/crop.py +0 -0
  124. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/extract.py +0 -0
  125. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/gap_fill.py +0 -0
  126. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/inventory.py +0 -0
  127. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/outcome.py +0 -0
  128. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/override.py +0 -0
  129. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/placement.py +0 -0
  130. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/raster.py +0 -0
  131. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/scrub.py +0 -0
  132. {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/vector.py +0 -0
  133. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/__init__.py +0 -0
  134. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/convert_inputs.py +0 -0
  135. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/convert_routes.py +0 -0
  136. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/demo.py +0 -0
  137. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/downloads.py +0 -0
  138. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/exporting.py +0 -0
  139. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/figures_view.py +0 -0
  140. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/folder_picker.py +0 -0
  141. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/guard.py +0 -0
  142. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/lifecycle.py +0 -0
  143. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/schemas.py +0 -0
  144. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/alt-export.js +0 -0
  145. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/app.js +0 -0
  146. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/clean.js +0 -0
  147. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/export.js +0 -0
  148. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/figure-placement.js +0 -0
  149. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/figures.js +0 -0
  150. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/lifecycle.js +0 -0
  151. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/results.js +0 -0
  152. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/review.js +0 -0
  153. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/style.css +0 -0
  154. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/upload_utils.py +0 -0
  155. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/uploads_routes.py +0 -0
  156. {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/validation_view.py +0 -0
  157. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/__init__.py +0 -0
  158. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/_xml.py +0 -0
  159. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/archive_guard.py +0 -0
  160. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/citation_sentinels.py +0 -0
  161. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/docx_clean.py +0 -0
  162. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/filters.py +0 -0
  163. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/formats.py +0 -0
  164. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/frontmatter.py +0 -0
  165. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/headings.py +0 -0
  166. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_authors.py +0 -0
  167. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_body.py +0 -0
  168. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_guess.py +0 -0
  169. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_guess_nondocx.py +0 -0
  170. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_markers.py +0 -0
  171. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_paragraphs.py +0 -0
  172. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_schema.py +0 -0
  173. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/pandoc.py +0 -0
  174. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/portable_anchors.py +0 -0
  175. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/preflight.py +0 -0
  176. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/preflight_privacy.py +0 -0
  177. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/tables.py +0 -0
  178. {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/tables_degraded.py +0 -0
  179. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/__init__.py +0 -0
  180. {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/tex_cache.py +0 -0
  181. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/__init__.py +0 -0
  182. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/_compat.py +0 -0
  183. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/body.py +0 -0
  184. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/compile.py +0 -0
  185. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/emit.py +0 -0
  186. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/equations.py +0 -0
  187. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/figure.py +0 -0
  188. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/meta.py +0 -0
  189. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/preflight.py +0 -0
  190. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/reconcile.py +0 -0
  191. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/refs.py +0 -0
  192. {latextify-0.3.2 → latextify-0.3.4}/latextify/model/validate.py +0 -0
  193. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/__init__.py +0 -0
  194. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/docx_adapter.py +0 -0
  195. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/images.py +0 -0
  196. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/ole.py +0 -0
  197. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/opc.py +0 -0
  198. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pdf.py +0 -0
  199. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pdf_content.py +0 -0
  200. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pptx.py +0 -0
  201. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/registry.py +0 -0
  202. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/report.py +0 -0
  203. {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/xlsx.py +0 -0
  204. {latextify-0.3.2 → latextify-0.3.4}/latextify/report/__init__.py +0 -0
  205. {latextify-0.3.2 → latextify-0.3.4}/latextify/report/render.py +0 -0
  206. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/__init__.py +0 -0
  207. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/authors.py +0 -0
  208. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/.gitkeep +0 -0
  209. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/manifest.yaml +0 -0
  210. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/metadata.tex.j2 +0 -0
  211. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/preamble.tex.j2 +0 -0
  212. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-advances/manifest.yaml +0 -0
  213. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-apl/manifest.yaml +0 -0
  214. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-jap/manifest.yaml +0 -0
  215. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prapplied/manifest.yaml +0 -0
  216. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prl/manifest.yaml +0 -0
  217. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prx/manifest.yaml +0 -0
  218. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-rmp/manifest.yaml +0 -0
  219. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/manifest.yaml +0 -0
  220. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/metadata.tex.j2 +0 -0
  221. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/preamble.tex.j2 +0 -0
  222. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/vendor/elsarticle.cls +0 -0
  223. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/manifest.yaml +0 -0
  224. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/metadata.tex.j2 +0 -0
  225. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/preamble.tex.j2 +0 -0
  226. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/VENDOR_LICENSE.txt +0 -0
  227. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/manifest.yaml +0 -0
  228. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/metadata.tex.j2 +0 -0
  229. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/preamble.tex.j2 +0 -0
  230. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/.gitattributes +0 -0
  231. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart.cls +0 -0
  232. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart10.clo +0 -0
  233. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart12.clo +0 -0
  234. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/manifest.yaml +0 -0
  235. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/metadata.tex.j2 +0 -0
  236. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/preamble.tex.j2 +0 -0
  237. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/VENDOR_LICENSE.txt +0 -0
  238. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/manifest.yaml +0 -0
  239. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/metadata.tex.j2 +0 -0
  240. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/preamble.tex.j2 +0 -0
  241. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/.gitattributes +0 -0
  242. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-jnl.cls +0 -0
  243. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-mathphys-ay.bst +0 -0
  244. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-mathphys-num.bst +0 -0
  245. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/manifest.yaml +0 -0
  246. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/metadata.tex.j2 +0 -0
  247. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/preamble.tex.j2 +0 -0
  248. {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/loader.py +0 -0
  249. {latextify-0.3.2 → latextify-0.3.4}/plans/FORMATS_AND_PRIVACY_PLAN.md +0 -0
  250. {latextify-0.3.2 → latextify-0.3.4}/plans/GUI_MULTIFILE_PLAN.md +0 -0
  251. {latextify-0.3.2 → latextify-0.3.4}/plans/GUI_OPTIONS_FORMATS_PLAN.md +0 -0
  252. {latextify-0.3.2 → latextify-0.3.4}/plans/METADATA_PRIVACY_PLAN.md +0 -0
  253. {latextify-0.3.2 → latextify-0.3.4}/plans/VECTOR_FIGURES_PLAN.md +0 -0
  254. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/GUI_JOURNALS_EXPORT_PLAN.md +0 -0
  255. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/LATEXTIFY_PLAN.md +0 -0
  256. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/MANUSCRIPT_FIDELITY_PLAN.md +0 -0
  257. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/OFFLINE_PORTABILITY_PLAN.md +0 -0
  258. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/REPO_HEALTH_PLAN.md +0 -0
  259. {latextify-0.3.2 → latextify-0.3.4}/plans/archive/SECURITY_RELIABILITY_AUDIT_PLAN.md +0 -0
  260. {latextify-0.3.2 → latextify-0.3.4}/render.yaml +0 -0
  261. {latextify-0.3.2 → latextify-0.3.4}/startup.sh +0 -0
  262. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/README.md +0 -0
  263. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/bracket_cited.docx +0 -0
  264. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/clean.docx +0 -0
  265. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/clean_black_figure.pdf +0 -0
  266. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/cropped_figure.docx +0 -0
  267. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/endnote_cited.docx +0 -0
  268. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/equations.docx +0 -0
  269. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/figures.docx +0 -0
  270. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/achemso_metadata.tex +0 -0
  271. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/achemso_preamble.tex +0 -0
  272. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_metadata.tex +0 -0
  273. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_preamble_authoryear.tex +0 -0
  274. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_preamble_numeric.tex +0 -0
  275. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/ieeetran_metadata.tex +0 -0
  276. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/ieeetran_preamble.tex +0 -0
  277. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/iopart_metadata.tex +0 -0
  278. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/iopart_preamble.tex +0 -0
  279. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/revtex4-2_metadata.tex +0 -0
  280. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/revtex4-2_preamble.tex +0 -0
  281. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_metadata.tex +0 -0
  282. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_preamble.tex +0 -0
  283. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_preamble_authoryear.tex +0 -0
  284. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_metadata.tex +0 -0
  285. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_preamble_authoryear.tex +0 -0
  286. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_preamble_numeric.tex +0 -0
  287. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/hand_cited.docx +0 -0
  288. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_book.xlsx +0 -0
  289. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_deck.pptx +0 -0
  290. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_doc.pdf +0 -0
  291. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_files.truth.json +0 -0
  292. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_photo.jpg +0 -0
  293. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_bracket_cited.py +0 -0
  294. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_clean.py +0 -0
  295. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_cropped_figure.py +0 -0
  296. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_endnote_cited.py +0 -0
  297. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_equations.py +0 -0
  298. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_figures.py +0 -0
  299. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_hand_cited.py +0 -0
  300. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_leaky_files.py +0 -0
  301. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_metadata_titlepage.py +0 -0
  302. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_supplement.py +0 -0
  303. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_tables.py +0 -0
  304. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_unsupported.py +0 -0
  305. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_wordnative_cited.py +0 -0
  306. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_zotero_cited.py +0 -0
  307. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/metadata_titlepage.docx +0 -0
  308. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/paper.yaml +0 -0
  309. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/supplement.docx +0 -0
  310. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/tables.docx +0 -0
  311. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/unsupported.docx +0 -0
  312. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/wordnative_cited.docx +0 -0
  313. {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/zotero_cited.docx +0 -0
  314. {latextify-0.3.2 → latextify-0.3.4}/tests/test_archive_guard.py +0 -0
  315. {latextify-0.3.2 → latextify-0.3.4}/tests/test_audit_equations.py +0 -0
  316. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citation_sentinels.py +0 -0
  317. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bib.py +0 -0
  318. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bibmatch.py +0 -0
  319. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bibtex_in.py +0 -0
  320. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bracket_refs.py +0 -0
  321. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_compile_stub.py +0 -0
  322. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_corrections.py +0 -0
  323. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_crossref.py +0 -0
  324. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_csl_json_in.py +0 -0
  325. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_degradation.py +0 -0
  326. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote.py +0 -0
  327. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote_compile.py +0 -0
  328. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote_xml_in.py +0 -0
  329. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract.py +0 -0
  330. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract_endnote.py +0 -0
  331. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract_wordnative.py +0 -0
  332. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_fields.py +0 -0
  333. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_merge.py +0 -0
  334. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_nbib_in.py +0 -0
  335. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_parsers.py +0 -0
  336. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_plaintext.py +0 -0
  337. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_reconstruct.py +0 -0
  338. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_refs_import.py +0 -0
  339. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_stress.py +0 -0
  340. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_validate.py +0 -0
  341. {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_wordnative.py +0 -0
  342. {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli_figures.py +0 -0
  343. {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli_review.py +0 -0
  344. {latextify-0.3.2 → latextify-0.3.4}/tests/test_compat_strenum.py +0 -0
  345. {latextify-0.3.2 → latextify-0.3.4}/tests/test_compile_logs.py +0 -0
  346. {latextify-0.3.2 → latextify-0.3.4}/tests/test_compile_tectonic.py +0 -0
  347. {latextify-0.3.2 → latextify-0.3.4}/tests/test_docx_clean.py +0 -0
  348. {latextify-0.3.2 → latextify-0.3.4}/tests/test_emit.py +0 -0
  349. {latextify-0.3.2 → latextify-0.3.4}/tests/test_emit_submission.py +0 -0
  350. {latextify-0.3.2 → latextify-0.3.4}/tests/test_examples.py +0 -0
  351. {latextify-0.3.2 → latextify-0.3.4}/tests/test_export_formats.py +0 -0
  352. {latextify-0.3.2 → latextify-0.3.4}/tests/test_fidelity_captions_reflist.py +0 -0
  353. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figure_placement.py +0 -0
  354. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures.py +0 -0
  355. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_caption_gaps.py +0 -0
  356. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_convert.py +0 -0
  357. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_crop.py +0 -0
  358. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_inventory.py +0 -0
  359. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_scrub.py +0 -0
  360. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_stage2.py +0 -0
  361. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_tiff.py +0 -0
  362. {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_wide.py +0 -0
  363. {latextify-0.3.2 → latextify-0.3.4}/tests/test_filters.py +0 -0
  364. {latextify-0.3.2 → latextify-0.3.4}/tests/test_filters_headings.py +0 -0
  365. {latextify-0.3.2 → latextify-0.3.4}/tests/test_frontmatter.py +0 -0
  366. {latextify-0.3.2 → latextify-0.3.4}/tests/test_gui_demo.py +0 -0
  367. {latextify-0.3.2 → latextify-0.3.4}/tests/test_inline_citations.py +0 -0
  368. {latextify-0.3.2 → latextify-0.3.4}/tests/test_inline_supplement.py +0 -0
  369. {latextify-0.3.2 → latextify-0.3.4}/tests/test_journal_pdf_layout.py +0 -0
  370. {latextify-0.3.2 → latextify-0.3.4}/tests/test_manuscript_formats.py +0 -0
  371. {latextify-0.3.2 → latextify-0.3.4}/tests/test_metadata_guess.py +0 -0
  372. {latextify-0.3.2 → latextify-0.3.4}/tests/test_package.py +0 -0
  373. {latextify-0.3.2 → latextify-0.3.4}/tests/test_pandoc.py +0 -0
  374. {latextify-0.3.2 → latextify-0.3.4}/tests/test_pdf_combine.py +0 -0
  375. {latextify-0.3.2 → latextify-0.3.4}/tests/test_portable.py +0 -0
  376. {latextify-0.3.2 → latextify-0.3.4}/tests/test_preflight.py +0 -0
  377. {latextify-0.3.2 → latextify-0.3.4}/tests/test_preflight_privacy.py +0 -0
  378. {latextify-0.3.2 → latextify-0.3.4}/tests/test_privacy.py +0 -0
  379. {latextify-0.3.2 → latextify-0.3.4}/tests/test_repo_integrity.py +0 -0
  380. {latextify-0.3.2 → latextify-0.3.4}/tests/test_report.py +0 -0
  381. {latextify-0.3.2 → latextify-0.3.4}/tests/test_supplement.py +0 -0
  382. {latextify-0.3.2 → latextify-0.3.4}/tests/test_tables.py +0 -0
  383. {latextify-0.3.2 → latextify-0.3.4}/tests/test_tectonic_integrity.py +0 -0
  384. {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates.py +0 -0
  385. {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates_item22.py +0 -0
  386. {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates_sn_jnl.py +0 -0
  387. {latextify-0.3.2 → latextify-0.3.4}/tests/test_xml_hardening.py +0 -0
@@ -147,14 +147,18 @@ jobs:
147
147
  with:
148
148
  python-version: "3.13"
149
149
  - name: Install
150
- run: uv sync --locked --group portable
150
+ run: |
151
+ uv sync --locked --group portable
152
+ # setup-uv may select GitHub's hosted interpreter, which is not a
153
+ # relocatable payload. Install an explicit uv-managed copy to bundle.
154
+ uv python install 3.13 --no-bin --no-registry
151
155
  - name: Set up the TARGET Python 3.10 (what install.py will run under)
152
156
  id: py310
153
157
  uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
154
158
  with:
155
159
  python-version: "3.10"
156
- - name: Build a GUI kit covering Python 3.10 and warm one journal (network ON)
157
- run: uv run latextify make-kit --target current --python-versions 3.10 --with-gui --journals revtex4-2 --output build
160
+ - name: Build a GUI/dev kit covering Python 3.10 and 3.13 (network ON)
161
+ run: uv run latextify make-kit --target current --python-versions 3.10 --python-versions 3.13 --with-gui --with-dev --journals revtex4-2 --output build
158
162
  - name: Install the kit under Python 3.10, network POISONED
159
163
  env:
160
164
  # Same reasoning as the Linux offline-kit job: uppercase only, one
@@ -197,6 +201,8 @@ jobs:
197
201
  Get-Content "build/portable/LaTeXtify-Windows-Portable/latextify-startup.log" -ErrorAction SilentlyContinue
198
202
  throw "portable self-test failed (exit $($selfTest.ExitCode))"
199
203
  }
204
+ $verify = Start-Process -FilePath $app -ArgumentList "--verify-installation" -PassThru -Wait -WindowStyle Hidden
205
+ if ($verify.ExitCode -ne 0) { throw "portable integrity verification failed" }
200
206
  $env:LATEXTIFY_NO_BROWSER = "1"
201
207
  $env:LATEXTIFY_PORT = "8765"
202
208
  $process = Start-Process -FilePath $app -PassThru -WindowStyle Hidden
@@ -220,3 +226,42 @@ jobs:
220
226
  } finally {
221
227
  if (-not $process.HasExited) { Stop-Process -Id $process.Id -Force }
222
228
  }
229
+ - name: Build and exercise the editable offline repository
230
+ env:
231
+ HTTPS_PROXY: http://127.0.0.1:9
232
+ HTTP_PROXY: http://127.0.0.1:9
233
+ ALL_PROXY: http://127.0.0.1:9
234
+ run: |
235
+ $python = uv python find --managed-python 3.13
236
+ uv run --group portable python tools/build_windows_offline_repo.py `
237
+ --kit build/latextify-offline-windows-x64 `
238
+ --python-runtime $python `
239
+ --output build/offline-repo
240
+ if ($LASTEXITCODE -ne 0) { throw "offline repository build failed" }
241
+ $repo = Resolve-Path "build/offline-repo/LaTeXtify-Windows-Offline-Repo"
242
+ & "$repo/.runtime/python/python.exe" "$repo/.offline-kit/install.py" --dir $repo
243
+ if ($LASTEXITCODE -ne 0) { throw "offline repository setup failed" }
244
+ Push-Location $repo
245
+ try {
246
+ $env:LATEXTIFY_OFFLINE = "1"
247
+ $env:PATH = "$repo/.offline-kit/tectonic;$env:PATH"
248
+ $env:TECTONIC_CACHE_DIR = "$repo/.offline-kit/tex-bundle-cache"
249
+ & ".venv/Scripts/python.exe" -c "import pathlib, latextify; assert pathlib.Path(latextify.__file__).resolve().is_relative_to(pathlib.Path.cwd())"
250
+ if ($LASTEXITCODE -ne 0) { throw "offline repository did not import editable source" }
251
+ & ".venv/Scripts/python.exe" -m pytest -q tests/test_portable.py
252
+ if ($LASTEXITCODE -ne 0) { throw "offline repository test command failed" }
253
+ & ".runtime/python/python.exe" "verify_installation.py"
254
+ if ($LASTEXITCODE -ne 0) { throw "offline repository integrity verification failed" }
255
+ & ".venv/Scripts/python.exe" -m latextify convert `
256
+ examples/04-combined-emf/Combined-Manuscript-with-EMF.docx `
257
+ -j revtex4-2 -o offline-repo-demo --pdf --inline-supplement `
258
+ --columns two --inline-supplement-columns one `
259
+ --figure-column 1=one --figure-column 2=two
260
+ if ($LASTEXITCODE -ne 0) { throw "combined Word/EMF scenario failed" }
261
+ $body = Get-Content "offline-repo-demo/revtex4-2/generated/body.tex" -Raw
262
+ foreach ($marker in @("\begin{figure}", "\begin{figure*}", "\clearpage", "\onecolumn")) {
263
+ if (-not $body.Contains($marker)) { throw "combined Word/EMF output is missing $marker" }
264
+ }
265
+ } finally {
266
+ Pop-Location
267
+ }
@@ -1,10 +1,9 @@
1
1
  name: Publish to PyPI
2
2
 
3
- # Publishes the sdist + wheel to PyPI. Triggers ONLY on a published GitHub
4
- # Release -- never on a plain push, a pull request, or even a tag push (tag
5
- # pushes drive release.yml's offline-kit build instead). This is the
6
- # machinery only: it cannot fire a real publish until an OWNER completes the
7
- # two one-time setup steps below.
3
+ # Publishes the sdist + wheel to PyPI. Normally dispatched by release.yml only
4
+ # after every offline artifact has built and passed its acceptance tests. The
5
+ # published-release trigger remains as a backwards-compatible/manual path.
6
+ # Neither a plain branch push nor a pull request can publish a package.
8
7
  #
9
8
  # ---------------------------------------------------------------------------
10
9
  # OWNER SETUP REQUIRED before the first real publish (both are one-time,
@@ -21,17 +20,25 @@ name: Publish to PyPI
21
20
  # successful publish from this trusted publisher -- no manual project
22
21
  # creation needed.)
23
22
  #
24
- # 2. Publish a GitHub Release (e.g. tag v0.1.0). The `release: published`
25
- # event below is what triggers the `publish` job -- nothing publishes
26
- # before that happens.
23
+ # 2. Push a version tag (e.g. v0.1.0). release.yml builds and verifies all
24
+ # artifacts, creates a draft GitHub release, dispatches this workflow for
25
+ # that exact tag, and publishes the GitHub release only after PyPI passes.
27
26
  # ---------------------------------------------------------------------------
28
27
 
29
28
  on:
30
29
  release:
31
30
  types: [published]
31
+ workflow_dispatch:
32
+ inputs:
33
+ tag:
34
+ description: "Exact version tag to build and publish"
35
+ required: true
36
+ type: string
37
+
38
+ run-name: Publish ${{ inputs.tag || github.event.release.tag_name }} to PyPI
32
39
 
33
40
  concurrency:
34
- group: publish-${{ github.ref }}
41
+ group: publish-${{ inputs.tag || github.event.release.tag_name }}
35
42
  cancel-in-progress: false
36
43
 
37
44
  permissions:
@@ -42,6 +49,8 @@ jobs:
42
49
  runs-on: ubuntu-latest
43
50
  steps:
44
51
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
52
+ with:
53
+ ref: ${{ inputs.tag || github.event.release.tag_name }}
45
54
  - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
46
55
  # No python-version here on purpose: setup-uv reads .python-version,
47
56
  # so the repo file is the single declaration (toolchain-version rule).
@@ -70,3 +79,5 @@ jobs:
70
79
  name: dist
71
80
  path: dist/
72
81
  - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
82
+ with:
83
+ skip-existing: true
@@ -1,10 +1,9 @@
1
1
  name: Release kits
2
2
 
3
- # On a version tag, build the three offline kits and attach them (plus a
4
- # source zip and checksums) to a GitHub release, so an air-gapped machine can
5
- # "download from the releases page" with no online build host at all.
6
- # Complements the CI `offline-kit` job, which proves one kit installs and
7
- # compiles a PDF offline on every push.
3
+ # On a version tag, build and test the native Windows portable app, editable
4
+ # offline repository, three platform kits, source archive, and checksums. The
5
+ # assets stay in a draft release while the exact tag is published to PyPI; the
6
+ # GitHub release becomes public only after every preceding step succeeds.
8
7
 
9
8
  on:
10
9
  push:
@@ -21,6 +20,7 @@ on:
21
20
 
22
21
  permissions:
23
22
  contents: write # create the release and upload assets
23
+ actions: write # dispatch and verify the trusted PyPI publishing workflow
24
24
 
25
25
  concurrency:
26
26
  group: release-${{ github.ref }}
@@ -45,11 +45,15 @@ jobs:
45
45
  ~/.cache/Tectonic
46
46
  key: tectonic-${{ runner.os }}-v1
47
47
  - name: Install build dependencies
48
- run: uv sync --locked --no-dev --extra gui --group portable
48
+ run: |
49
+ uv sync --locked --no-dev --extra gui --group portable
50
+ # The hosted interpreter is runner infrastructure, not a portable
51
+ # payload. Install a complete uv-managed runtime for the repo bundle.
52
+ uv python install 3.13 --no-bin --no-registry
49
53
  - name: Build native Windows runtime assets
50
54
  env:
51
55
  GITHUB_TOKEN: ${{ github.token }}
52
- run: uv run latextify make-kit --target current --python-versions 3.13 --with-gui -o build
56
+ run: uv run latextify make-kit --target current --python-versions 3.13 --with-gui --with-dev -o build
53
57
  - name: Freeze and verify the portable application
54
58
  env:
55
59
  HTTPS_PROXY: http://127.0.0.1:9
@@ -63,10 +67,82 @@ jobs:
63
67
  Get-Content "build/portable/LaTeXtify-Windows-Portable/latextify-startup.log" -ErrorAction SilentlyContinue
64
68
  throw "portable self-test failed (exit $($selfTest.ExitCode))"
65
69
  }
70
+ $verify = Start-Process -FilePath $app -ArgumentList "--verify-installation" -PassThru -Wait -WindowStyle Hidden
71
+ if ($verify.ExitCode -ne 0) { throw "portable integrity verification failed" }
72
+
73
+ - name: Build and verify the editable offline repository
74
+ env:
75
+ HTTPS_PROXY: http://127.0.0.1:9
76
+ HTTP_PROXY: http://127.0.0.1:9
77
+ ALL_PROXY: http://127.0.0.1:9
78
+ run: |
79
+ # setup-uv already installed this managed interpreter. Copying its
80
+ # complete runtime makes the target independent of system Python.
81
+ $python = uv python find --managed-python 3.13
82
+ uv run --group portable python tools/build_windows_offline_repo.py `
83
+ --kit build/latextify-offline-windows-x64 `
84
+ --python-runtime $python `
85
+ --output build/offline-repo
86
+ if ($LASTEXITCODE -ne 0) { throw "offline repository build failed" }
87
+
88
+ $repo = Resolve-Path "build/offline-repo/LaTeXtify-Windows-Offline-Repo"
89
+ $process = Start-Process -FilePath "cmd.exe" `
90
+ -ArgumentList "/c", "startup.bat --port 8766 --no-browser --keep-alive" `
91
+ -WorkingDirectory $repo -PassThru -WindowStyle Hidden
92
+ try {
93
+ $ready = $false
94
+ for ($i = 0; $i -lt 60; $i++) {
95
+ Start-Sleep -Seconds 1
96
+ try {
97
+ $response = Invoke-WebRequest "http://127.0.0.1:8766/" -UseBasicParsing -NoProxy
98
+ if ($response.StatusCode -eq 200 -and $response.Content -match "LaTeXtify") {
99
+ $ready = $true
100
+ break
101
+ }
102
+ } catch {}
103
+ if ($process.HasExited) { break }
104
+ }
105
+ if (-not $ready) {
106
+ Get-Content "$repo/latextify-startup.log" -ErrorAction SilentlyContinue
107
+ throw "offline repository GUI did not start"
108
+ }
109
+ } finally {
110
+ if (-not $process.HasExited) { Stop-Process -Id $process.Id -Force }
111
+ }
112
+
113
+ Push-Location $repo
114
+ try {
115
+ $env:LATEXTIFY_OFFLINE = "1"
116
+ $env:PATH = "$repo/.offline-kit/tectonic;$env:PATH"
117
+ $env:TECTONIC_CACHE_DIR = "$repo/.offline-kit/tex-bundle-cache"
118
+ & ".venv/Scripts/python.exe" -c "import pathlib, latextify; assert pathlib.Path(latextify.__file__).resolve().is_relative_to(pathlib.Path.cwd())"
119
+ if ($LASTEXITCODE -ne 0) { throw "offline repository did not import editable source" }
120
+ & ".venv/Scripts/python.exe" -m pytest -q tests/test_portable.py
121
+ if ($LASTEXITCODE -ne 0) { throw "offline repository test command failed" }
122
+ & ".runtime/python/python.exe" "verify_installation.py"
123
+ if ($LASTEXITCODE -ne 0) { throw "offline repository integrity verification failed" }
124
+ & ".venv/Scripts/python.exe" -m latextify convert `
125
+ examples/04-combined-emf/Combined-Manuscript-with-EMF.docx `
126
+ -j revtex4-2 -o offline-repo-demo --pdf --inline-supplement `
127
+ --columns two --inline-supplement-columns one `
128
+ --figure-column 1=one --figure-column 2=two
129
+ if ($LASTEXITCODE -ne 0) { throw "offline repository conversion failed" }
130
+ if (-not (Test-Path "offline-repo-demo/revtex4-2/main.pdf")) {
131
+ throw "offline repository did not compile a PDF"
132
+ }
133
+ $body = Get-Content "offline-repo-demo/revtex4-2/generated/body.tex" -Raw
134
+ foreach ($marker in @("\begin{figure}", "\begin{figure*}", "\clearpage", "\onecolumn")) {
135
+ if (-not $body.Contains($marker)) { throw "combined Word/EMF output is missing $marker" }
136
+ }
137
+ } finally {
138
+ Pop-Location
139
+ }
66
140
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
67
141
  with:
68
- name: windows-portable
69
- path: build/portable/LaTeXtify-Windows-Portable.zip
142
+ name: windows-offline-packages
143
+ path: |
144
+ build/portable/LaTeXtify-Windows-Portable.zip
145
+ build/offline-repo/LaTeXtify-Windows-Offline-Repo.zip
70
146
  if-no-files-found: error
71
147
 
72
148
  build-kits:
@@ -161,16 +237,22 @@ jobs:
161
237
 
162
238
  - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
163
239
  with:
164
- name: windows-portable
240
+ name: windows-offline-packages
165
241
  path: build
166
242
 
167
- - name: Add the portable Windows application to checksums
243
+ - name: Add the Windows packages to checksums
168
244
  run: |
169
245
  cd build
246
+ # upload-artifact preserves the common `build/`-relative directory
247
+ # structure when given files from two different subdirectories.
248
+ # Flatten those two known assets before checksumming/uploading them.
249
+ mv portable/LaTeXtify-Windows-Portable.zip .
250
+ mv offline-repo/LaTeXtify-Windows-Offline-Repo.zip .
170
251
  sha256sum LaTeXtify-Windows-Portable.zip >> SHA256SUMS.txt
252
+ sha256sum LaTeXtify-Windows-Offline-Repo.zip >> SHA256SUMS.txt
171
253
  cat SHA256SUMS.txt
172
254
 
173
- - name: Create release (if missing) and upload assets
255
+ - name: Create draft release (if missing) and upload assets
174
256
  env:
175
257
  GH_TOKEN: ${{ github.token }}
176
258
  TAG: ${{ github.event.inputs.tag || github.ref_name }}
@@ -181,6 +263,7 @@ jobs:
181
263
  latextify-offline-linux-x64.zip
182
264
  latextify-offline-macos-arm64.zip
183
265
  LaTeXtify-Windows-Portable.zip
266
+ LaTeXtify-Windows-Offline-Repo.zip
184
267
  latextify-source.zip
185
268
  SHA256SUMS.txt
186
269
  )
@@ -191,6 +274,37 @@ jobs:
191
274
  else
192
275
  gh release create "$TAG" \
193
276
  --title "LaTeXtify $TAG" \
277
+ --draft \
194
278
  --generate-notes \
195
279
  "${assets[@]}"
196
280
  fi
281
+
282
+ - name: Publish the exact tag to PyPI and wait for it
283
+ env:
284
+ GH_TOKEN: ${{ github.token }}
285
+ TAG: ${{ github.event.inputs.tag || github.ref_name }}
286
+ run: |
287
+ tag_sha=$(git rev-parse "$TAG^{commit}")
288
+ previous_id=$(gh run list --workflow publish.yml --event workflow_dispatch \
289
+ --commit "$tag_sha" --limit 1 --json databaseId \
290
+ --jq '.[0].databaseId // empty')
291
+ gh workflow run publish.yml --ref "$TAG" -f tag="$TAG"
292
+ run_id=""
293
+ for attempt in $(seq 1 30); do
294
+ candidate=$(gh run list --workflow publish.yml --event workflow_dispatch \
295
+ --commit "$tag_sha" --limit 1 --json databaseId \
296
+ --jq '.[0].databaseId // empty')
297
+ if [ -n "$candidate" ] && [ "$candidate" != "$previous_id" ]; then
298
+ run_id="$candidate"
299
+ break
300
+ fi
301
+ sleep 2
302
+ done
303
+ [ -n "$run_id" ] || { echo "PyPI workflow did not start" >&2; exit 1; }
304
+ gh run watch "$run_id" --exit-status
305
+
306
+ - name: Publish the verified GitHub release
307
+ env:
308
+ GH_TOKEN: ${{ github.token }}
309
+ TAG: ${{ github.event.inputs.tag || github.ref_name }}
310
+ run: gh release edit "$TAG" --draft=false
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: latextify
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Convert Word manuscripts to journal-ready LaTeX projects and PDFs
5
5
  Project-URL: Homepage, https://github.com/pquarterman17/LaTeXtify
6
6
  Project-URL: Repository, https://github.com/pquarterman17/LaTeXtify
@@ -331,8 +331,10 @@ To start the web GUI without touching a command line, double-click
331
331
  **`startup.bat`** (Windows) or run **`./startup.sh`** (macOS/Linux). It installs
332
332
  dependencies on first run, opens the GUI in your browser, and — if anything
333
333
  goes wrong — writes an easy-to-find `latextify-startup.log` next to the script
334
- and prints it for you to copy. This source-tree launcher needs internet access
335
- on its first run.
334
+ and prints it for you to copy. On Windows, `startup.bat` is offline-first and
335
+ never downloads missing software. A connected source checkout can explicitly
336
+ opt into the old online bootstrap by running **`startup-online.bat`** instead.
337
+ The macOS/Linux source launcher still needs internet access on its first run.
336
338
 
337
339
  ### Offline / firewalled Windows computer
338
340
 
@@ -360,6 +362,37 @@ Python already present on the work computer. Embedded EMF/WMF figures work,
360
362
  but preserving them as vectors requires an offline installation of LibreOffice
361
363
  or Inkscape; otherwise Windows attempts a 600-DPI raster fallback.
362
364
 
365
+ For an **editable source checkout** on an air-gapped Windows computer, use
366
+ **`LaTeXtify-Windows-Offline-Repo.zip`**. It contains the complete tracked
367
+ repository, a portable Python 3.13 runtime, pinned runtime and development
368
+ dependencies, Pandoc, Tectonic, and the warmed TeX cache. Extract the whole
369
+ folder and double-click `startup.bat`; its first launch creates `.venv` from
370
+ the local wheelhouse without contacting any service. Code changes under
371
+ `latextify\` are used on the next launch, and the bundled environment can run
372
+ the offline test, lint, and type-check commands described in
373
+ `README-OFFLINE-REPO.txt`.
374
+
375
+ Both Windows downloads include `Verify-LaTeXtify.bat` and a file-level
376
+ integrity manifest. Run it after transfer/extraction if antivirus, endpoint
377
+ security, or an incomplete unzip may have removed a component. The GUI also
378
+ has a **System check** panel that tests Pandoc, Tectonic, the TeX cache,
379
+ writable storage, offline PDF compilation, and the available EMF/WMF path,
380
+ then saves a content-free report suitable for IT.
381
+
382
+ The downloads also include the synthetic combined Word+EMF acceptance sample.
383
+ It is the same merged main-text + supplement scenario exercised by the release
384
+ gate and can be used to check a work computer before opening an unpublished
385
+ manuscript.
386
+
387
+ These packages serve different purposes:
388
+
389
+ | Release asset | Intended use | Python required |
390
+ |---|---|---|
391
+ | `LaTeXtify-Windows-Portable.zip` | Normal GUI use | No |
392
+ | `LaTeXtify-Windows-Offline-Repo.zip` | Editable/debuggable/testable source | No |
393
+ | `latextify-offline-windows-x64.zip` | Inspectable installed Python package | Yes |
394
+ | GitHub/source ZIP | Connected development | Yes |
395
+
363
396
  ## Usage
364
397
 
365
398
  > Installed from source with `uv sync`? Prefix these with `uv run` (e.g.
@@ -380,6 +413,10 @@ latextify convert paper.docx --journal revtex4-2 --supplement si.docx --pdf
380
413
  # Material", or "Supporting Information" at the boundary.
381
414
  latextify convert merged.docx --journal revtex4-2 --inline-supplement --pdf
382
415
 
416
+ # Switch the inline supplement to one column after the page break
417
+ latextify convert merged.docx --journal revtex4-2 --inline-supplement \
418
+ --columns two --inline-supplement-columns one --pdf
419
+
383
420
  # Inline supplements cannot be combined with --figures-at-end: delayed floats
384
421
  # would cross the numbering boundary. LaTeXtify rejects that combination.
385
422
  # If the merged file contains separate main and supplementary reference lists,
@@ -285,8 +285,10 @@ To start the web GUI without touching a command line, double-click
285
285
  **`startup.bat`** (Windows) or run **`./startup.sh`** (macOS/Linux). It installs
286
286
  dependencies on first run, opens the GUI in your browser, and — if anything
287
287
  goes wrong — writes an easy-to-find `latextify-startup.log` next to the script
288
- and prints it for you to copy. This source-tree launcher needs internet access
289
- on its first run.
288
+ and prints it for you to copy. On Windows, `startup.bat` is offline-first and
289
+ never downloads missing software. A connected source checkout can explicitly
290
+ opt into the old online bootstrap by running **`startup-online.bat`** instead.
291
+ The macOS/Linux source launcher still needs internet access on its first run.
290
292
 
291
293
  ### Offline / firewalled Windows computer
292
294
 
@@ -314,6 +316,37 @@ Python already present on the work computer. Embedded EMF/WMF figures work,
314
316
  but preserving them as vectors requires an offline installation of LibreOffice
315
317
  or Inkscape; otherwise Windows attempts a 600-DPI raster fallback.
316
318
 
319
+ For an **editable source checkout** on an air-gapped Windows computer, use
320
+ **`LaTeXtify-Windows-Offline-Repo.zip`**. It contains the complete tracked
321
+ repository, a portable Python 3.13 runtime, pinned runtime and development
322
+ dependencies, Pandoc, Tectonic, and the warmed TeX cache. Extract the whole
323
+ folder and double-click `startup.bat`; its first launch creates `.venv` from
324
+ the local wheelhouse without contacting any service. Code changes under
325
+ `latextify\` are used on the next launch, and the bundled environment can run
326
+ the offline test, lint, and type-check commands described in
327
+ `README-OFFLINE-REPO.txt`.
328
+
329
+ Both Windows downloads include `Verify-LaTeXtify.bat` and a file-level
330
+ integrity manifest. Run it after transfer/extraction if antivirus, endpoint
331
+ security, or an incomplete unzip may have removed a component. The GUI also
332
+ has a **System check** panel that tests Pandoc, Tectonic, the TeX cache,
333
+ writable storage, offline PDF compilation, and the available EMF/WMF path,
334
+ then saves a content-free report suitable for IT.
335
+
336
+ The downloads also include the synthetic combined Word+EMF acceptance sample.
337
+ It is the same merged main-text + supplement scenario exercised by the release
338
+ gate and can be used to check a work computer before opening an unpublished
339
+ manuscript.
340
+
341
+ These packages serve different purposes:
342
+
343
+ | Release asset | Intended use | Python required |
344
+ |---|---|---|
345
+ | `LaTeXtify-Windows-Portable.zip` | Normal GUI use | No |
346
+ | `LaTeXtify-Windows-Offline-Repo.zip` | Editable/debuggable/testable source | No |
347
+ | `latextify-offline-windows-x64.zip` | Inspectable installed Python package | Yes |
348
+ | GitHub/source ZIP | Connected development | Yes |
349
+
317
350
  ## Usage
318
351
 
319
352
  > Installed from source with `uv sync`? Prefix these with `uv run` (e.g.
@@ -334,6 +367,10 @@ latextify convert paper.docx --journal revtex4-2 --supplement si.docx --pdf
334
367
  # Material", or "Supporting Information" at the boundary.
335
368
  latextify convert merged.docx --journal revtex4-2 --inline-supplement --pdf
336
369
 
370
+ # Switch the inline supplement to one column after the page break
371
+ latextify convert merged.docx --journal revtex4-2 --inline-supplement \
372
+ --columns two --inline-supplement-columns one --pdf
373
+
337
374
  # Inline supplements cannot be combined with --figures-at-end: delayed floats
338
375
  # would cross the numbering boundary. LaTeXtify rejects that combination.
339
376
  # If the merged file contains separate main and supplementary reference lists,
@@ -0,0 +1,19 @@
1
+ LaTeXtify combined Word + EMF acceptance sample
2
+ ================================================
3
+
4
+ Combined-Manuscript-with-EMF.docx contains synthetic main text followed by a
5
+ "Supplementary Information" heading and two real embedded Windows EMF figures.
6
+ It contains no research data.
7
+
8
+ Recommended GUI choices:
9
+
10
+ Combined main + supplement: Main two columns; supplement one column
11
+ Figure 1 width: One column
12
+ Figure 2 width: Two columns
13
+ Compile PDF: On
14
+
15
+ The output should be one main.pdf with a page break before the supplement,
16
+ S-numbering after the boundary, and both figures visible. Without LibreOffice
17
+ or Inkscape, LaTeXtify should report that the EMFs were rasterized at 600 DPI.
18
+
19
+ make_sample.py regenerates the document on Windows and is not needed to use it.
@@ -0,0 +1,114 @@
1
+ """Create the Windows acceptance sample: merged main/SI DOCX with real EMFs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ctypes
6
+ import zipfile
7
+ from ctypes import wintypes
8
+ from pathlib import Path
9
+
10
+ from docx import Document
11
+ from docx.shared import Inches
12
+ from PIL import Image
13
+
14
+ HERE = Path(__file__).resolve().parent
15
+ OUTPUT = HERE / "Combined-Manuscript-with-EMF.docx"
16
+
17
+
18
+ def _write_emf(path: Path, *, tall: bool) -> None:
19
+ gdi32 = ctypes.WinDLL("gdi32", use_last_error=True)
20
+ gdi32.CreateEnhMetaFileW.argtypes = (
21
+ wintypes.HDC,
22
+ wintypes.LPCWSTR,
23
+ ctypes.POINTER(wintypes.RECT),
24
+ wintypes.LPCWSTR,
25
+ )
26
+ gdi32.CreateEnhMetaFileW.restype = wintypes.HANDLE
27
+ gdi32.Rectangle.argtypes = (
28
+ wintypes.HDC,
29
+ ctypes.c_int,
30
+ ctypes.c_int,
31
+ ctypes.c_int,
32
+ ctypes.c_int,
33
+ )
34
+ gdi32.CloseEnhMetaFile.argtypes = (wintypes.HDC,)
35
+ gdi32.CloseEnhMetaFile.restype = wintypes.HANDLE
36
+ gdi32.DeleteEnhMetaFile.argtypes = (wintypes.HANDLE,)
37
+ frame = wintypes.RECT(0, 0, 1270 if tall else 2540, 2540 if tall else 1270)
38
+ hdc = gdi32.CreateEnhMetaFileW(None, str(path), ctypes.byref(frame), "LaTeXtify\0EMF sample\0")
39
+ if not hdc:
40
+ raise ctypes.WinError(ctypes.get_last_error())
41
+ gdi32.Rectangle(hdc, 100, 100, frame.right - 100, frame.bottom - 100)
42
+ metafile = gdi32.CloseEnhMetaFile(hdc)
43
+ if not metafile:
44
+ raise ctypes.WinError(ctypes.get_last_error())
45
+ gdi32.DeleteEnhMetaFile(metafile)
46
+
47
+
48
+ def _replace_pngs(docx_path: Path, emfs: tuple[Path, ...]) -> None:
49
+ rebuilt = docx_path.with_suffix(".rebuilt.docx")
50
+ with (
51
+ zipfile.ZipFile(docx_path) as source,
52
+ zipfile.ZipFile(rebuilt, "w", zipfile.ZIP_DEFLATED) as destination,
53
+ ):
54
+ image_names = {f"word/media/image{index}.png" for index in range(1, len(emfs) + 1)}
55
+ for info in source.infolist():
56
+ if info.filename in image_names:
57
+ continue
58
+ data = source.read(info.filename)
59
+ if info.filename == "word/_rels/document.xml.rels":
60
+ data = data.replace(b".png", b".emf")
61
+ elif info.filename == "[Content_Types].xml":
62
+ data = data.replace(
63
+ b"</Types>",
64
+ b'<Default Extension="emf" ContentType="image/x-emf"/></Types>',
65
+ )
66
+ destination.writestr(info, data)
67
+ for index, emf in enumerate(emfs, start=1):
68
+ destination.writestr(f"word/media/image{index}.emf", emf.read_bytes())
69
+ rebuilt.replace(docx_path)
70
+
71
+
72
+ def main() -> None:
73
+ if not hasattr(ctypes, "WinDLL"):
74
+ raise SystemExit("This sample must be generated on Windows.")
75
+ main_emf, supplement_emf = HERE / "main.emf", HERE / "supplement.emf"
76
+ main_png, supplement_png = HERE / "main.png", HERE / "supplement.png"
77
+ try:
78
+ _write_emf(main_emf, tall=True)
79
+ _write_emf(supplement_emf, tall=False)
80
+ Image.new("RGB", (200, 400), "white").save(main_png)
81
+ Image.new("RGB", (400, 200), "white").save(supplement_png)
82
+
83
+ doc = Document()
84
+ doc.core_properties.title = "LaTeXtify combined manuscript acceptance sample"
85
+ doc.core_properties.author = "Example Author"
86
+ doc.add_heading("A Combined Manuscript Acceptance Sample", level=0)
87
+ doc.add_paragraph("Example Author")
88
+ doc.add_heading("Abstract", level=1)
89
+ doc.add_paragraph(
90
+ "This synthetic document verifies offline conversion without containing research data."
91
+ )
92
+ doc.add_heading("Results", level=1)
93
+ doc.add_paragraph("The main text contains an embedded Windows Enhanced Metafile.")
94
+ doc.add_picture(str(main_png), width=Inches(2.0))
95
+ doc.add_paragraph("Figure 1. Main-text EMF intended for one column.")
96
+ doc.add_paragraph("A demonstration result is cited here [1].")
97
+ doc.add_heading("References", level=1)
98
+ doc.add_paragraph("[1] Example, A. A synthetic reference. Example Journal 1, 1–2 (2026).")
99
+ doc.add_heading("Supplementary Information", level=1)
100
+ doc.add_paragraph("This section must begin on a new page and use S-numbering.")
101
+ doc.add_picture(str(supplement_png), width=Inches(5.5))
102
+ doc.add_paragraph("Figure S1. Supplementary EMF intended to span two columns.")
103
+ doc.add_heading("Supplementary Methods", level=2)
104
+ doc.add_paragraph("No external data or network service is required for this sample.")
105
+ doc.save(OUTPUT)
106
+ _replace_pngs(OUTPUT, (main_emf, supplement_emf))
107
+ print(OUTPUT)
108
+ finally:
109
+ for temporary in (main_emf, supplement_emf, main_png, supplement_png):
110
+ temporary.unlink(missing_ok=True)
111
+
112
+
113
+ if __name__ == "__main__":
114
+ main()
@@ -1,16 +1,17 @@
1
1
  # LaTeXtify usage examples
2
2
 
3
- Three self-contained, runnable examples covering the input shapes a real user
4
- hits, from the simplest to the full journal submission. Each folder has a
5
- `make_manuscript.py` that **generates** its Word document(s) (no binary files
6
- are committed — the same python-docx / hand-assembled-OOXML approach the test
7
- suite uses) and a `run.py` that generates + converts to a PDF in one step.
3
+ Four self-contained examples cover the input shapes a real user hits, from the
4
+ simplest to the full journal submission. Examples 01–03 generate their inputs
5
+ on demand. Example 04 intentionally includes a ready-to-use synthetic Word
6
+ file with real embedded Windows EMFs so an offline machine can be checked
7
+ without first installing development tools.
8
8
 
9
9
  | # | Example | Scenario | Highlights |
10
10
  |---|---------|----------|------------|
11
11
  | 01 | [all-embedded](01-all-embedded/) | One `.docx` with everything inside | embedded figures · metadata guessing · typed references → **Crossref** reconstruction |
12
12
  | 02 | [word-plus-figures](02-word-plus-figures/) | `.docx` + separate figure files | `figures/` folder convention · `figures.yaml` manifest · override precedence |
13
13
  | 03 | [multipart-refmanager](03-multipart-refmanager/) | Main + supplement + reference manager | Zotero/Mendeley **field codes** · `--supplement` · shared/de-duplicated `references.bib` · `paper.yaml` metadata |
14
+ | 04 | [combined-emf](04-combined-emf/) | One merged main+supplement `.docx` with embedded EMFs | page-break boundary · S-numbering · manual one-/two-column figures · offline acceptance sample |
14
15
 
15
16
  ## Quick start
16
17
 
@@ -45,6 +46,9 @@ warmed TeX cache.
45
46
  document as reference-manager field codes (a clean, offline bibliography);
46
47
  `--supplement` emits the SI into the same project with a shared, de-duplicated
47
48
  bibliography.
49
+ - **"My main text and supplement are one Word file and the figures are EMFs."**
50
+ → [Example 04](04-combined-emf/). Use the committed sample directly in the
51
+ GUI; its README lists the expected layout choices and output.
48
52
 
49
53
  ## How references get in — at a glance
50
54
 
@@ -56,4 +60,4 @@ ingest a standalone `.bib`, `.ris`, or reference-manager library file.
56
60
  | Inserted by a Zotero/Mendeley/EndNote **Word plugin** (field codes) | metadata read straight from the field codes | No — DOIs and all metadata are embedded |
57
61
  | Word's **built-in** citation manager | read from the document's citation sources | No |
58
62
  | A **typed** reference list + `[1]`/`(Smith 2020)` markers | reconstructed via **Crossref**, low-confidence entries flagged `verify` | Yes (offline → raw verify-flagged entries) |
59
- | A separate exported **library file** (`.bib`/`.ris`/CSL-JSON) | **not supported** — insert citations with the Word plugin instead | — |
63
+ | A separate exported **library file** (`.bib`/`.ris`/CSL-JSON/EndNote XML/`.nbib`) | upload it with the References role or pass `--references` | No for matched entries |