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.
- {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/ci.yml +48 -3
- {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/publish.yml +20 -9
- {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/release.yml +126 -12
- {latextify-0.3.2 → latextify-0.3.4}/PKG-INFO +40 -3
- {latextify-0.3.2 → latextify-0.3.4}/README.md +39 -2
- latextify-0.3.4/examples/04-combined-emf/README.txt +19 -0
- latextify-0.3.4/examples/04-combined-emf/make_sample.py +114 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/README.md +10 -6
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_convert.py +12 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_kit.py +6 -0
- latextify-0.3.4/latextify/gui/diagnostics_routes.py +20 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/server.py +2 -0
- latextify-0.3.4/latextify/gui/static/diagnostics.js +44 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/index.html +14 -0
- latextify-0.3.4/latextify/integrity.py +128 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/README-OFFLINE.md +4 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/build.py +10 -4
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/install_template.py +8 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/target.py +2 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/portable.py +42 -2
- latextify-0.3.4/latextify/system_check.py +143 -0
- latextify-0.3.4/packaging/README-WINDOWS-OFFLINE-REPO.txt +67 -0
- {latextify-0.3.2 → latextify-0.3.4}/packaging/README-WINDOWS-PORTABLE.txt +11 -0
- latextify-0.3.4/packaging/Verify-LaTeXtify-Portable.bat +15 -0
- latextify-0.3.4/packaging/Verify-LaTeXtify-Repo.bat +14 -0
- latextify-0.3.4/packaging/verify_installation.py +23 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/OFFLINE_DISTRIBUTION_PLAN.md +34 -22
- {latextify-0.3.2 → latextify-0.3.4}/pyproject.toml +1 -1
- latextify-0.3.4/startup-online.bat +5 -0
- {latextify-0.3.2 → latextify-0.3.4}/startup.bat +46 -7
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli.py +52 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_gui.py +26 -0
- latextify-0.3.4/tests/test_integrity.py +46 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_kit_build.py +28 -0
- latextify-0.3.4/tests/test_offline_repo.py +62 -0
- latextify-0.3.4/tests/test_system_check.py +38 -0
- latextify-0.3.4/tools/build_windows_offline_repo.py +175 -0
- {latextify-0.3.2 → latextify-0.3.4}/tools/build_windows_portable.py +21 -0
- {latextify-0.3.2 → latextify-0.3.4}/uv.lock +1 -1
- {latextify-0.3.2 → latextify-0.3.4}/.dockerignore +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.gitattributes +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.github/dependabot.yml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/codeql.yml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.github/workflows/dependency-audit.yml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.gitignore +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/.python-version +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/CONTRIBUTING.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/LICENSE +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/NOTICE +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/SECURITY.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/DEPLOY.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/Dockerfile +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/README.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/hf-space/warm_cache.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/render/DEPLOY.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/deploy/render/Dockerfile +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/.gitignore +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/README.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/make_manuscript.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/01-all-embedded/run.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/.gitignore +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/README.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/make_manuscript.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/02-word-plus-figures/run.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/.gitignore +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/README.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/make_manuscript.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/examples/03-multipart-refmanager/run.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/__main__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/audit/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/audit/equations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/authoryear_index.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bib.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bibmatch.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/bibtex_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/body_markers.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/corrections.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/crossref.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/csl_json_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/endnote.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/endnote_xml_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/fields.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/mendeley.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/merge.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/nbib_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/plaintext.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/reconcile.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/reflist_nondocx.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/refs_import.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/validate.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/wordnative.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/citations/zotero.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_batch.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_equations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_export.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_figures.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_privacy.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/cli_review.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/logs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/pdf.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/compile/tectonic.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/alt_formats.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/alt_formats_render.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/anchors.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/bibliography.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/citation_resolution.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/figures_copy.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/figures_stage.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/inline_supplement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/metadata.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/output_dir.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/project.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/submission.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/emit/supplement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/caption_gaps.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/convert.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/crop.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/extract.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/gap_fill.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/inventory.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/outcome.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/override.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/placement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/raster.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/scrub.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/figures/vector.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/convert_inputs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/convert_routes.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/demo.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/downloads.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/exporting.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/figures_view.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/folder_picker.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/guard.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/lifecycle.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/schemas.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/alt-export.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/app.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/clean.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/export.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/figure-placement.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/figures.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/lifecycle.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/results.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/review.js +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/static/style.css +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/upload_utils.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/uploads_routes.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/gui/validation_view.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/_xml.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/archive_guard.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/citation_sentinels.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/docx_clean.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/filters.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/formats.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/frontmatter.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/headings.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_authors.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_body.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_guess.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_guess_nondocx.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_markers.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_paragraphs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/metadata_schema.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/pandoc.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/portable_anchors.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/preflight.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/preflight_privacy.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/tables.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/ingest/tables_degraded.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/kit/tex_cache.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/_compat.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/body.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/compile.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/emit.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/equations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/figure.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/meta.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/preflight.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/reconcile.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/refs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/model/validate.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/docx_adapter.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/images.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/ole.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/opc.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pdf.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pdf_content.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/pptx.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/registry.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/report.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/privacy/xlsx.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/report/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/report/render.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/__init__.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/authors.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/.gitkeep +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/achemso/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-advances/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-apl/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aip-jap/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prapplied/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prl/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-prx/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/aps-rmp/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/elsarticle/vendor/elsarticle.cls +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/ieeetran/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/VENDOR_LICENSE.txt +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/.gitattributes +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart.cls +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart10.clo +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/iopart/vendor/iopart12.clo +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/revtex4-2/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/VENDOR_LICENSE.txt +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/.gitattributes +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-jnl.cls +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-mathphys-ay.bst +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/sn-jnl/vendor/sn-mathphys-num.bst +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/manifest.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/metadata.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/journals/wiley/preamble.tex.j2 +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/latextify/templates/loader.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/FORMATS_AND_PRIVACY_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/GUI_MULTIFILE_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/GUI_OPTIONS_FORMATS_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/METADATA_PRIVACY_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/VECTOR_FIGURES_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/GUI_JOURNALS_EXPORT_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/LATEXTIFY_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/MANUSCRIPT_FIDELITY_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/OFFLINE_PORTABILITY_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/REPO_HEALTH_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/plans/archive/SECURITY_RELIABILITY_AUDIT_PLAN.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/render.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/startup.sh +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/README.md +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/bracket_cited.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/clean.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/clean_black_figure.pdf +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/cropped_figure.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/endnote_cited.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/equations.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/figures.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/achemso_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/achemso_preamble.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_preamble_authoryear.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/elsarticle_preamble_numeric.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/ieeetran_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/ieeetran_preamble.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/iopart_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/iopart_preamble.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/revtex4-2_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/revtex4-2_preamble.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_preamble.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/sn-jnl_preamble_authoryear.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_metadata.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_preamble_authoryear.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/golden/wiley_preamble_numeric.tex +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/hand_cited.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_book.xlsx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_deck.pptx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_doc.pdf +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_files.truth.json +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/leaky_photo.jpg +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_bracket_cited.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_clean.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_cropped_figure.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_endnote_cited.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_equations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_figures.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_hand_cited.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_leaky_files.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_metadata_titlepage.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_supplement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_tables.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_unsupported.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_wordnative_cited.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/make_zotero_cited.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/metadata_titlepage.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/paper.yaml +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/supplement.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/tables.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/unsupported.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/wordnative_cited.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/fixtures/zotero_cited.docx +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_archive_guard.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_audit_equations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citation_sentinels.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bib.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bibmatch.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bibtex_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_bracket_refs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_compile_stub.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_corrections.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_crossref.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_csl_json_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_degradation.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote_compile.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_endnote_xml_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract_endnote.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_extract_wordnative.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_fields.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_merge.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_nbib_in.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_parsers.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_plaintext.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_reconstruct.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_refs_import.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_stress.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_validate.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_citations_wordnative.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli_figures.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_cli_review.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_compat_strenum.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_compile_logs.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_compile_tectonic.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_docx_clean.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_emit.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_emit_submission.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_examples.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_export_formats.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_fidelity_captions_reflist.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figure_placement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_caption_gaps.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_convert.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_crop.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_inventory.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_scrub.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_stage2.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_tiff.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_figures_wide.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_filters.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_filters_headings.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_frontmatter.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_gui_demo.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_inline_citations.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_inline_supplement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_journal_pdf_layout.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_manuscript_formats.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_metadata_guess.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_package.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_pandoc.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_pdf_combine.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_portable.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_preflight.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_preflight_privacy.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_privacy.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_repo_integrity.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_report.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_supplement.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_tables.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_tectonic_integrity.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates_item22.py +0 -0
- {latextify-0.3.2 → latextify-0.3.4}/tests/test_templates_sn_jnl.py +0 -0
- {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:
|
|
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
|
|
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.
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
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.
|
|
25
|
-
#
|
|
26
|
-
#
|
|
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.
|
|
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
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
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:
|
|
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-
|
|
69
|
-
path:
|
|
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-
|
|
240
|
+
name: windows-offline-packages
|
|
165
241
|
path: build
|
|
166
242
|
|
|
167
|
-
- name: Add the
|
|
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.
|
|
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.
|
|
335
|
-
|
|
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.
|
|
289
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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) |
|
|
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 |
|