rxiv-maker 1.16.6__tar.gz → 1.16.8__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 (401) hide show
  1. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/.gitignore +1 -2
  2. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/CHANGELOG.md +57 -0
  3. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/PKG-INFO +10 -5
  4. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/README.md +8 -3
  5. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/pyproject.toml +1 -1
  6. rxiv_maker-1.16.8/src/docs/api/README.md +4 -0
  7. rxiv_maker-1.16.8/src/docs/api/index.md +4 -0
  8. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/__version__.py +1 -1
  9. rxiv_maker-1.16.8/src/rxiv_maker/cli/commands/docx.py +177 -0
  10. rxiv_maker-1.16.8/src/rxiv_maker/cli/commands/upgrade.py +52 -0
  11. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/dependency_manager.py +12 -0
  12. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/exporters/docx_exporter.py +100 -3
  13. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/exporters/docx_writer.py +38 -3
  14. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/bst_generator.py +27 -7
  15. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/docx_helpers.py +23 -2
  16. rxiv_maker-1.16.8/src/rxiv_maker/utils/rich_upgrade_notifier.py +162 -0
  17. rxiv_maker-1.16.8/tests/unit/test_bst_generator.py +132 -0
  18. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_dependency_package_names.py +37 -0
  19. rxiv_maker-1.16.8/tests/unit/test_docx_doi_resolution.py +248 -0
  20. rxiv_maker-1.16.8/tests/unit/test_rich_upgrade_notifier.py +206 -0
  21. rxiv_maker-1.16.8/tests/unit/test_upgrade_command.py +134 -0
  22. rxiv_maker-1.16.6/src/docs/api/README.md +0 -28
  23. rxiv_maker-1.16.6/src/docs/api/__version__.py.md +0 -9
  24. rxiv_maker-1.16.6/src/docs/api/author_name_formatter.py.md +0 -165
  25. rxiv_maker-1.16.6/src/docs/api/bibliography_parser.py.md +0 -123
  26. rxiv_maker-1.16.6/src/docs/api/cache_utils.py.md +0 -150
  27. rxiv_maker-1.16.6/src/docs/api/changelog_parser.py.md +0 -260
  28. rxiv_maker-1.16.6/src/docs/api/citation_utils.py.md +0 -78
  29. rxiv_maker-1.16.6/src/docs/api/email_encoder.py.md +0 -126
  30. rxiv_maker-1.16.6/src/docs/api/error_codes.py.md +0 -49
  31. rxiv_maker-1.16.6/src/docs/api/figure_utils.py.md +0 -253
  32. rxiv_maker-1.16.6/src/docs/api/github.py.md +0 -312
  33. rxiv_maker-1.16.6/src/docs/api/homebrew_checker.py.md +0 -99
  34. rxiv_maker-1.16.6/src/docs/api/index.md +0 -28
  35. rxiv_maker-1.16.6/src/docs/api/install_detector.py.md +0 -81
  36. rxiv_maker-1.16.6/src/docs/api/logging_config.py.md +0 -371
  37. rxiv_maker-1.16.6/src/docs/api/operation_ids.py.md +0 -218
  38. rxiv_maker-1.16.6/src/docs/api/platform.py.md +0 -527
  39. rxiv_maker-1.16.6/src/docs/api/python_execution_reporter.py.md +0 -302
  40. rxiv_maker-1.16.6/src/docs/api/text_utils.py.md +0 -71
  41. rxiv_maker-1.16.6/src/docs/api/unicode_safe.py.md +0 -230
  42. rxiv_maker-1.16.6/src/docs/api/url_to_doi.py.md +0 -80
  43. rxiv_maker-1.16.6/src/docs/api/validate.py.md +0 -142
  44. rxiv_maker-1.16.6/src/rxiv_maker/cli/commands/docx.py +0 -103
  45. rxiv_maker-1.16.6/src/rxiv_maker/cli/commands/upgrade.py +0 -164
  46. rxiv_maker-1.16.6/tests/unit/test_upgrade_command.py +0 -193
  47. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/LICENSE +0 -0
  48. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/logo/logo-rxiv-maker.afdesign +0 -0
  49. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/logo/logo-rxiv-maker.png +0 -0
  50. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/logo/logo-rxiv-maker.svg +0 -0
  51. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/__init__.py +0 -0
  52. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/__init__.py +0 -0
  53. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/__main__.py +0 -0
  54. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/__init__.py +0 -0
  55. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/arxiv.py +0 -0
  56. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/bibliography.py +0 -0
  57. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/build.py +0 -0
  58. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/cache_management.py +0 -0
  59. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/changelog.py +0 -0
  60. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/check_installation.py +0 -0
  61. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/clean.py +0 -0
  62. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/completion.py +0 -0
  63. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/config.py +0 -0
  64. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/create_repo.py +0 -0
  65. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/figures.py +0 -0
  66. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/get_rxiv_preprint.py +0 -0
  67. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/init.py +0 -0
  68. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/install_deps.py +0 -0
  69. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/repo_init.py +0 -0
  70. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/repos.py +0 -0
  71. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/repos_search.py +0 -0
  72. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/setup.py +0 -0
  73. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/track_changes.py +0 -0
  74. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/validate.py +0 -0
  75. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/commands/version.py +0 -0
  76. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/__init__.py +0 -0
  77. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/base.py +0 -0
  78. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/cache_commands.py +0 -0
  79. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/config_commands.py +0 -0
  80. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/content_commands.py +0 -0
  81. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/decorators.py +0 -0
  82. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/utility_commands.py +0 -0
  83. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework/workflow_commands.py +0 -0
  84. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/framework.py +0 -0
  85. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/interactive.py +0 -0
  86. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/interactive_prompts.py +0 -0
  87. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/cli/main.py +0 -0
  88. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/config/defaults.py +0 -0
  89. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/config/validator.py +0 -0
  90. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/__init__.py +0 -0
  91. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/citation_processor.py +0 -0
  92. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/code_processor.py +0 -0
  93. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/comment_processor.py +0 -0
  94. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/custom_command_processor.py +0 -0
  95. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/figure_processor.py +0 -0
  96. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/html_processor.py +0 -0
  97. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/list_processor.py +0 -0
  98. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/math_processor.py +0 -0
  99. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/md2tex.py +0 -0
  100. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/python_executor.py +0 -0
  101. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/section_processor.py +0 -0
  102. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/supplementary_note_processor.py +0 -0
  103. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/table_processor.py +0 -0
  104. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/text_formatters.py +0 -0
  105. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/types.py +0 -0
  106. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/converters/url_processor.py +0 -0
  107. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/__init__.py +0 -0
  108. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/advanced_cache.py +0 -0
  109. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/bibliography_cache.py +0 -0
  110. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/cache_utils.py +0 -0
  111. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/doi_cache.py +0 -0
  112. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/cache/secure_cache_utils.py +0 -0
  113. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/content_processor.py +0 -0
  114. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/environment_bootstrap.py +0 -0
  115. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/environment_manager.py +0 -0
  116. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/error_codes.py +0 -0
  117. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/error_recovery.py +0 -0
  118. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/logging_config.py +0 -0
  119. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/__init__.py +0 -0
  120. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/cache_manager.py +0 -0
  121. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/config_manager.py +0 -0
  122. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/execution_manager.py +0 -0
  123. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/file_manager.py +0 -0
  124. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/install_manager.py +0 -0
  125. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/state_manager.py +0 -0
  126. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/unified_config_manager.py +0 -0
  127. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/validation_manager.py +0 -0
  128. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/managers/workflow_manager.py +0 -0
  129. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/path_manager.py +0 -0
  130. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/progress_framework.py +0 -0
  131. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/repo_config.py +0 -0
  132. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/repository.py +0 -0
  133. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/session_optimizer.py +0 -0
  134. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/core/validation_framework.py +0 -0
  135. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/data/tips.yaml +0 -0
  136. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/__init__.py +0 -0
  137. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/__init__.py +0 -0
  138. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/add_bibliography.py +0 -0
  139. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/build_manager.py +0 -0
  140. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/cleanup.py +0 -0
  141. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/fix_bibliography.py +0 -0
  142. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/generate_docs.py +0 -0
  143. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/generate_figures.py +0 -0
  144. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/generate_preprint.py +0 -0
  145. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/prepare_arxiv.py +0 -0
  146. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/setup_environment.py +0 -0
  147. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/track_changes.py +0 -0
  148. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/validate.py +0 -0
  149. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/engines/operations/validate_pdf.py +0 -0
  150. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/exporters/__init__.py +0 -0
  151. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/exporters/docx_citation_mapper.py +0 -0
  152. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/exporters/docx_content_processor.py +0 -0
  153. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/__init__.py +0 -0
  154. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/dependency_handlers/__init__.py +0 -0
  155. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/dependency_handlers/latex.py +0 -0
  156. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/dependency_handlers/r_lang.py +0 -0
  157. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/dependency_handlers/system_libs.py +0 -0
  158. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/platform_installers/__init__.py +0 -0
  159. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/platform_installers/base.py +0 -0
  160. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/platform_installers/linux.py +0 -0
  161. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/platform_installers/macos.py +0 -0
  162. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/platform_installers/windows.py +0 -0
  163. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/utils/__init__.py +0 -0
  164. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/utils/logging.py +0 -0
  165. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/utils/progress.py +0 -0
  166. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/install/utils/verification.py +0 -0
  167. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/manuscript_utils/__init__.py +0 -0
  168. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/manuscript_utils/figure_utils.py +0 -0
  169. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/processors/__init__.py +0 -0
  170. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/processors/author_processor.py +0 -0
  171. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/processors/markdown_preprocessor.py +0 -0
  172. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/processors/template_processor.py +0 -0
  173. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/processors/yaml_processor.py +0 -0
  174. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/rxiv_maker_cli.py +0 -0
  175. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/scripts/__init__.py +0 -0
  176. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/scripts/custom_doc_generator.py +0 -0
  177. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/scripts/validate_manuscript.py +0 -0
  178. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/__init__.py +0 -0
  179. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/base.py +0 -0
  180. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/build_service.py +0 -0
  181. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/configuration_service.py +0 -0
  182. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/manuscript_service.py +0 -0
  183. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/publication_service.py +0 -0
  184. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/services/validation_service.py +0 -0
  185. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/templates/__init__.py +0 -0
  186. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/templates/manager.py +0 -0
  187. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/templates/registry.py +0 -0
  188. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/tex/python_execution_section.tex +0 -0
  189. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/__init__.py +0 -0
  190. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/author_name_formatter.py +0 -0
  191. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/bibliography_checksum.py +0 -0
  192. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/bibliography_parser.py +0 -0
  193. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/changelog_parser.py +0 -0
  194. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/citation_utils.py +0 -0
  195. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/dependency_checker.py +0 -0
  196. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/doi_resolver.py +0 -0
  197. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/email_encoder.py +0 -0
  198. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/figure_checksum.py +0 -0
  199. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/file_helpers.py +0 -0
  200. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/github.py +0 -0
  201. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/homebrew_checker.py +0 -0
  202. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/install_detector.py +0 -0
  203. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/operation_ids.py +0 -0
  204. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/pdf_utils.py +0 -0
  205. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/performance.py +0 -0
  206. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/platform.py +0 -0
  207. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/python_execution_reporter.py +0 -0
  208. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/retry.py +0 -0
  209. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/text_utils.py +0 -0
  210. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/tips.py +0 -0
  211. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/title_sync.py +0 -0
  212. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/unicode_safe.py +0 -0
  213. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/update_checker.py +0 -0
  214. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/utils/url_to_doi.py +0 -0
  215. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validate.py +0 -0
  216. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/__init__.py +0 -0
  217. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/base_validator.py +0 -0
  218. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/citation_validator.py +0 -0
  219. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/doi/__init__.py +0 -0
  220. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/doi/api_clients.py +0 -0
  221. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/doi/metadata_comparator.py +0 -0
  222. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/doi_validator.py +0 -0
  223. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/figure_validator.py +0 -0
  224. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/latex_error_parser.py +0 -0
  225. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/math_validator.py +0 -0
  226. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/pdf_validator.py +0 -0
  227. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/reference_validator.py +0 -0
  228. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/rxiv_maker/validators/syntax_validator.py +0 -0
  229. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/tex/style/rxiv_maker_style.bst +0 -0
  230. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/tex/style/rxiv_maker_style.cls +0 -0
  231. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/src/tex/template.tex +0 -0
  232. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/__init__.py +0 -0
  233. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/cli/__init__.py +0 -0
  234. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/cli/test_build.py +0 -0
  235. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/cli/test_changelog_command.py +0 -0
  236. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/cli/test_init_command.py +0 -0
  237. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/cli/test_main.py +0 -0
  238. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/conftest.py +0 -0
  239. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/e2e/__init__.py +0 -0
  240. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/e2e/test_dummy_manuscript_generator.py +0 -0
  241. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/e2e/test_figure_workflow_validation.py +0 -0
  242. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/00_CONFIG.yml +0 -0
  243. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/01_MAIN.md +0 -0
  244. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/03_REFERENCES.bib +0 -0
  245. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/FIGURES/Fig1.png +0 -0
  246. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/FIGURES/Fig2.png +0 -0
  247. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/FIGURES/Fig3.png +0 -0
  248. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/README.md +0 -0
  249. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/docx_export/sample_manuscript/01_MAIN.md +0 -0
  250. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/docx_export/sample_manuscript/02_SUPPLEMENTARY_INFO.md +0 -0
  251. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/docx_export/sample_manuscript/03_REFERENCES.bib +0 -0
  252. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/docx_export/sample_manuscript/2025__unknown_et_al__rxiv.docx +0 -0
  253. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/fixtures/docx_export/sample_manuscript/sample_manuscript.docx +0 -0
  254. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/__init__.py +0 -0
  255. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_article_generation.py +0 -0
  256. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_bibliography_author_format_docx.py +0 -0
  257. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_binary_distribution.py +0 -0
  258. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_centralized_components.py +0 -0
  259. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_citation_injection.py +0 -0
  260. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_comment_system_integration.py +0 -0
  261. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_docx_export_integration.py +0 -0
  262. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_doi_fallback_integration.py +0 -0
  263. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_doi_validation_integration.py +0 -0
  264. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_example_manuscript.py +0 -0
  265. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_guillaume_fixtures.py +0 -0
  266. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_homebrew_workflow_validation.py +0 -0
  267. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_infrastructure_suite.py +0 -0
  268. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_init_build_workflow.py +0 -0
  269. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_install_verification_integration.py +0 -0
  270. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_latex_dependency_integration.py +0 -0
  271. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_manuscript_directory_integration.py +0 -0
  272. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_manuscript_python_execution_reporting.py +0 -0
  273. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_practical_manuscript_workflows.py +0 -0
  274. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_pypi_package_integration.py +0 -0
  275. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_python_execution_integration.py +0 -0
  276. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_repository_cli_integration.py +0 -0
  277. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_supplementary_formatting.py +0 -0
  278. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_user_reported_issue.py +0 -0
  279. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/integration/test_validation_workflow.py +0 -0
  280. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/README.md +0 -0
  281. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/conftest.py +0 -0
  282. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_cli_argument_parsing.py +0 -0
  283. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_discord_reported_issues.py +0 -0
  284. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_error_message_quality.py +0 -0
  285. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_google_colab_integration.py +0 -0
  286. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_guillaume_edge_cases.py +0 -0
  287. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_guillaume_pr131_rewrite.py +0 -0
  288. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_path_resolution.py +0 -0
  289. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_widget_author_behavior.py +0 -0
  290. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/regression/test_widget_interactions_playwright.py +0 -0
  291. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/smoke/__init__.py +0 -0
  292. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/smoke/test_basic_functionality.py +0 -0
  293. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/smoke/test_cli_smoke.py +0 -0
  294. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/system/__init__.py +0 -0
  295. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/system/test_ci_matrix.py +0 -0
  296. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/system/test_cli_workflows.py +0 -0
  297. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/system/test_end_to_end.py +0 -0
  298. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/test_homebrew_checker.py +0 -0
  299. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/test_install_detector.py +0 -0
  300. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/__init__.py +0 -0
  301. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/exporters/__init__.py +0 -0
  302. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/exporters/test_docx_citation_mapper.py +0 -0
  303. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/exporters/test_docx_content_processor.py +0 -0
  304. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_add_bibliography.py +0 -0
  305. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_arxiv_command.py +0 -0
  306. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_async_execution_manager.py +0 -0
  307. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_author_name_formatter.py +0 -0
  308. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_author_processor.py +0 -0
  309. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_build_command.py +0 -0
  310. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_build_manager.py +0 -0
  311. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_build_manager_manuscript_path.py +0 -0
  312. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_cache_security.py +0 -0
  313. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_cache_utils.py +0 -0
  314. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_check_installation_command.py +0 -0
  315. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_citation_processor.py +0 -0
  316. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_citation_rendering.py +0 -0
  317. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_citation_style.py +0 -0
  318. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_citation_utils.py +0 -0
  319. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_cli_cleanup_integration.py +0 -0
  320. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_cli_structure.py +0 -0
  321. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_comment_processor.py +0 -0
  322. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_conda_installation_manager.py +0 -0
  323. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_conda_platform_detection.py +0 -0
  324. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_cross_platform_optimizations.py +0 -0
  325. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_custom_command_processor.py +0 -0
  326. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_dependency_manager.py +0 -0
  327. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_docx_helpers.py +0 -0
  328. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_doi_fallback_system.py +0 -0
  329. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_doi_resolver.py +0 -0
  330. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_doi_validator.py +0 -0
  331. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_email_encoder.py +0 -0
  332. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_environment_manager.py +0 -0
  333. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_error_handling_scenarios.py +0 -0
  334. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_execution_manager_comprehensive.py +0 -0
  335. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_figure_generator.py +0 -0
  336. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_figure_processor.py +0 -0
  337. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_figure_processor_error_handling.py +0 -0
  338. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_file_helpers.py +0 -0
  339. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_fix_bibliography.py +0 -0
  340. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_generate_docs.py +0 -0
  341. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_generate_preprint.py +0 -0
  342. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_github.py +0 -0
  343. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_github_actions_integration.py +0 -0
  344. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_importlib_edge_cases.py +0 -0
  345. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_install_platform_installers.py +0 -0
  346. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_install_system_libs.py +0 -0
  347. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_install_verification.py +0 -0
  348. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_interactive_path_change.py +0 -0
  349. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_interactive_validators.py +0 -0
  350. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_latex_dependency_handler.py +0 -0
  351. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_manuscript_figure_utils.py +0 -0
  352. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_manuscript_repository.py +0 -0
  353. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_math_processor.py +0 -0
  354. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_md2tex.py +0 -0
  355. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_mermaid_fallback.py +0 -0
  356. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_path_manager.py +0 -0
  357. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_pdf_validator.py +0 -0
  358. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_platform_comprehensive.py +0 -0
  359. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_platform_detector.py +0 -0
  360. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_processor_suite.py +0 -0
  361. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_python_execution_reporter.py +0 -0
  362. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_python_executor.py +0 -0
  363. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_release_orchestrator.py +0 -0
  364. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_repository_manager.py +0 -0
  365. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_rxiv_setup_command.py +0 -0
  366. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_security_features.py +0 -0
  367. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_security_scanner.py +0 -0
  368. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_setup_environment.py +0 -0
  369. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_style_file_resolution.py +0 -0
  370. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_supplementary_note_processor.py +0 -0
  371. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_table_rotation.py +0 -0
  372. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_template_processor.py +0 -0
  373. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_text_formatters.py +0 -0
  374. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_text_utils.py +0 -0
  375. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_tips.py +0 -0
  376. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_title_sync.py +0 -0
  377. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_title_sync_validation.py +0 -0
  378. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_track_changes.py +0 -0
  379. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_trailing_slash_regression.py +0 -0
  380. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_url_to_doi.py +0 -0
  381. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_utils.py +0 -0
  382. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_validate_backticks.py +0 -0
  383. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_validate_command_fixed.py +0 -0
  384. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_validate_manuscript.py +0 -0
  385. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_validation_suite.py +0 -0
  386. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_validators.py +0 -0
  387. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/unit/test_yaml_processor.py +0 -0
  388. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/README.md +0 -0
  389. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/00_CONFIG.yml +0 -0
  390. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/01_MAIN.md +0 -0
  391. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/03_REFERENCES.bib +0 -0
  392. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/FIGURES/Figure__positioning_test.png +0 -0
  393. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/FIGURES/Figure__positioning_test.py +0 -0
  394. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/FIGURES/ReadyFig.png +0 -0
  395. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/FIGURES/ReadyFig.py +0 -0
  396. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/figure-positioning/README.md +0 -0
  397. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/methods-placement/00_CONFIG.yml +0 -0
  398. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/methods-placement/01_MAIN.md +0 -0
  399. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/methods-placement/02_SUPPLEMENTARY_INFO.md +0 -0
  400. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/methods-placement/03_REFERENCES.bib +0 -0
  401. {rxiv_maker-1.16.6 → rxiv_maker-1.16.8}/tests/visual/methods-placement/README.md +0 -0
@@ -52,7 +52,6 @@ output.txt
52
52
  *~
53
53
 
54
54
  # Claude Code configuration
55
- !CLAUDE.md
56
55
  .claude
57
56
 
58
57
  # Byte-compiled / optimized / DLL files
@@ -316,6 +315,7 @@ GEMINI.md
316
315
  !CHANGELOG.md
317
316
  !CONTRIBUTING.md
318
317
  !CODE_OF_CONDUCT.md
318
+ !CLAUDE.md
319
319
  !docs/**/*.md
320
320
  !EXAMPLE_MANUSCRIPT/**/*.md
321
321
  !MANUSCRIPT/**/*.md
@@ -330,7 +330,6 @@ GEMINI.md
330
330
  todo*.md
331
331
  DOCKER_ACCELERATION.md
332
332
  GEMINI.md
333
- CLAUDE.md
334
333
  output.md
335
334
 
336
335
  # Temporary analysis files
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.16.8] - 2025-12-19
11
+
12
+ ### Added
13
+
14
+ - **Automatic Poppler Installation**: Interactive installation prompt for DOCX export on macOS
15
+ - Detects missing poppler utilities when exporting to DOCX with PDF figures
16
+ - Offers automatic installation via Homebrew with user confirmation
17
+ - Shows clear installation instructions for Linux (apt) and other platforms
18
+ - Gracefully falls back to placeholders when poppler unavailable
19
+ - **DOI Resolution Implementation**: `--resolve-dois` flag now fully functional for DOCX export
20
+ - Resolves missing DOIs using CrossRef API with intelligent title matching
21
+ - Cleans LaTeX commands from titles for accurate search results
22
+ - Validates matches using year information when available
23
+ - Handles network failures and timeouts gracefully
24
+ - Logs resolved DOIs for transparency
25
+ - **Poppler Dependency Tracking**: Registered poppler in DependencyManager
26
+ - Added as system binary dependency with alternatives (pdftoppm, pdfinfo)
27
+ - Included in `rxiv check-installation` output
28
+ - Provides platform-specific installation hints
29
+
30
+ ### Fixed
31
+
32
+ - **BST File Regex Bug**: Corrected bibliography style file generation to only modify `format.names`
33
+ - Previous regex matched both `format.names` and `format.full.names` functions
34
+ - Now specifically targets only `format.names` function using DOTALL flag
35
+ - Prevents corruption of citation labels in natbib
36
+ - Eliminates warning: "Found 2 format string patterns in .bst file"
37
+ - Raises error if unexpected matches found (defensive programming)
38
+ - **PDF to Image Conversion**: Improved error handling for missing poppler utilities
39
+ - Distinguishes between poppler not installed, corrupted PDFs, and other errors
40
+ - Uses proper logging instead of print statements
41
+ - Re-raises poppler errors to allow CLI to offer installation
42
+ - Provides specific error messages for different failure types
43
+
44
+ ### Changed
45
+
46
+ - **DOCX Export Experience**: Enhanced PDF figure embedding workflow
47
+ - Pre-flight check detects poppler availability before attempting conversion
48
+ - Caches poppler status to avoid repeated checks
49
+ - Shows helpful warnings with installation instructions
50
+ - PDF figures embed correctly when poppler is installed
51
+ - **Homebrew Formula**: Added poppler as dependency
52
+ - Users installing via `brew install rxiv-maker` now get poppler automatically
53
+ - Ensures DOCX export works out of the box for Homebrew users
54
+
55
+ ## [1.16.7] - 2025-12-18
56
+
57
+ ### Changed
58
+
59
+ - **Upgrade Workflow Centralization**: Migrated to henriqueslab-updater v1.2.0 for centralized upgrade management
60
+ - Simplified upgrade command implementation from 165 to 53 lines (68% reduction)
61
+ - Created custom `RxivUpgradeNotifier` implementing `UpgradeNotifier` protocol
62
+ - Integrated with existing changelog parser for rich change summaries with breaking change highlighting
63
+ - Maintains backward compatibility with all existing flags (`--yes`, `--check-only`)
64
+ - Reduces code duplication across HenriquesLab CLI tools
65
+ - Provides consistent upgrade UX across all HenriquesLab projects
66
+
10
67
  ## [1.16.6] - 2025-12-17
11
68
 
12
69
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rxiv-maker
3
- Version: 1.16.6
3
+ Version: 1.16.8
4
4
  Summary: Write scientific preprints in Markdown. Generate publication-ready PDFs efficiently.
5
5
  Project-URL: Homepage, https://github.com/HenriquesLab/rxiv-maker
6
6
  Project-URL: Documentation, https://github.com/HenriquesLab/rxiv-maker#readme
@@ -27,7 +27,7 @@ Requires-Python: >=3.10
27
27
  Requires-Dist: click>=8.0.0
28
28
  Requires-Dist: crossref-commons>=0.0.7
29
29
  Requires-Dist: gitpython>=3.1.0
30
- Requires-Dist: henriqueslab-updater>=1.1.3
30
+ Requires-Dist: henriqueslab-updater>=1.2.0
31
31
  Requires-Dist: latex2mathml>=3.78.0
32
32
  Requires-Dist: matplotlib>=3.7.0
33
33
  Requires-Dist: numpy>=1.24.0
@@ -358,9 +358,14 @@ rxiv config --non-interactive # Show current settings
358
358
 
359
359
  ### Maintenance
360
360
  ```bash
361
- rxiv upgrade # Upgrade to latest version
362
- rxiv changelog # View changelog and release notes
363
- rxiv changelog --recent 5 # View last 5 versions
361
+ # Upgrade commands (auto-detects Homebrew, pip, uv, pipx)
362
+ rxiv upgrade # Interactive upgrade with confirmation
363
+ rxiv upgrade --yes # Upgrade without confirmation
364
+ rxiv upgrade --check-only # Check for updates only
365
+
366
+ # Changelog and version information
367
+ rxiv changelog # View changelog and release notes
368
+ rxiv changelog --recent 5 # View last 5 versions
364
369
  ```
365
370
 
366
371
  > **💡 CI/Automation Note:** All interactive commands support non-interactive mode or configuration files for use in CI/CD pipelines and automated workflows. Use `--non-interactive` flag or configure via `~/.rxiv-maker/config` for non-TTY environments.
@@ -281,9 +281,14 @@ rxiv config --non-interactive # Show current settings
281
281
 
282
282
  ### Maintenance
283
283
  ```bash
284
- rxiv upgrade # Upgrade to latest version
285
- rxiv changelog # View changelog and release notes
286
- rxiv changelog --recent 5 # View last 5 versions
284
+ # Upgrade commands (auto-detects Homebrew, pip, uv, pipx)
285
+ rxiv upgrade # Interactive upgrade with confirmation
286
+ rxiv upgrade --yes # Upgrade without confirmation
287
+ rxiv upgrade --check-only # Check for updates only
288
+
289
+ # Changelog and version information
290
+ rxiv changelog # View changelog and release notes
291
+ rxiv changelog --recent 5 # View last 5 versions
287
292
  ```
288
293
 
289
294
  > **💡 CI/Automation Note:** All interactive commands support non-interactive mode or configuration files for use in CI/CD pipelines and automated workflows. Use `--non-interactive` flag or configure via `~/.rxiv-maker/config` for non-TTY environments.
@@ -53,7 +53,7 @@ dependencies = [
53
53
  "GitPython>=3.1.0",
54
54
  "prompt_toolkit>=3.0.0",
55
55
  # Update checking
56
- "henriqueslab-updater>=1.1.3",
56
+ "henriqueslab-updater>=1.2.0",
57
57
  ]
58
58
 
59
59
  [project.urls]
@@ -0,0 +1,4 @@
1
+ # API Documentation
2
+
3
+ Welcome to the API documentation for rxiv-maker.
4
+
@@ -0,0 +1,4 @@
1
+ # API Documentation
2
+
3
+ Welcome to the API documentation for rxiv-maker.
4
+
@@ -1,3 +1,3 @@
1
1
  """Version information."""
2
2
 
3
- __version__ = "1.16.6"
3
+ __version__ = "1.16.8"
@@ -0,0 +1,177 @@
1
+ """DOCX export command for rxiv-maker CLI."""
2
+
3
+ import platform
4
+ import shutil
5
+ import subprocess
6
+
7
+ import rich_click as click
8
+ from rich.console import Console
9
+
10
+ from ...core.logging_config import get_logger
11
+ from ...core.managers.dependency_manager import DependencyStatus, get_dependency_manager
12
+ from ...exporters.docx_exporter import DocxExporter
13
+
14
+ logger = get_logger()
15
+ console = Console()
16
+
17
+
18
+ def _check_and_offer_poppler_installation(console: Console, quiet: bool, verbose: bool) -> None:
19
+ """Check poppler availability and offer automatic installation via brew.
20
+
21
+ Args:
22
+ console: Rich console for output
23
+ quiet: Whether to suppress output
24
+ verbose: Whether verbose mode is enabled
25
+ """
26
+ # Check if poppler is installed
27
+ manager = get_dependency_manager()
28
+ result = manager.check_dependency("pdftoppm")
29
+
30
+ if result.status == DependencyStatus.AVAILABLE:
31
+ if verbose:
32
+ console.print("[dim]✓ Poppler utilities available[/dim]")
33
+ return
34
+
35
+ # Poppler is missing - offer to install
36
+ system = platform.system()
37
+
38
+ if system == "Darwin" and shutil.which("brew"):
39
+ # macOS with Homebrew
40
+ if not quiet:
41
+ console.print("[yellow]⚠️ Poppler not found[/yellow]")
42
+ console.print(" Poppler is needed to embed PDF figures in DOCX files.")
43
+ console.print(" Without it, PDF figures will appear as placeholders.")
44
+ console.print()
45
+
46
+ if click.confirm(" Would you like to install poppler now via Homebrew?", default=True):
47
+ console.print("[cyan]Installing poppler...[/cyan]")
48
+ try:
49
+ result = subprocess.run(
50
+ ["brew", "install", "poppler"],
51
+ capture_output=True,
52
+ text=True,
53
+ timeout=300,
54
+ )
55
+
56
+ if result.returncode == 0:
57
+ console.print("[green]✅ Poppler installed successfully![/green]")
58
+ # Clear dependency cache so it gets re-checked
59
+ manager.clear_cache()
60
+ else:
61
+ console.print(f"[red]❌ Installation failed:[/red] {result.stderr}")
62
+ console.print(" You can install manually with: brew install poppler")
63
+ except subprocess.TimeoutExpired:
64
+ console.print("[red]❌ Installation timed out[/red]")
65
+ except Exception as e:
66
+ console.print(f"[red]❌ Installation error:[/red] {e}")
67
+ else:
68
+ console.print(" [dim]Skipping poppler installation. PDF figures will show as placeholders.[/dim]")
69
+
70
+ elif system == "Linux":
71
+ # Linux
72
+ if not quiet:
73
+ console.print("[yellow]⚠️ Poppler not found[/yellow]")
74
+ console.print(" Install with: sudo apt install poppler-utils")
75
+ console.print()
76
+ else:
77
+ # Other platforms or brew not available
78
+ if not quiet:
79
+ console.print("[yellow]⚠️ Poppler not found[/yellow]")
80
+ console.print(f" Install instructions: {result.resolution_hint}")
81
+ console.print()
82
+
83
+
84
+ @click.command(context_settings={"help_option_names": ["-h", "--help"]})
85
+ @click.argument(
86
+ "manuscript_path",
87
+ type=click.Path(exists=True, file_okay=False),
88
+ required=False,
89
+ metavar="[MANUSCRIPT_PATH]",
90
+ )
91
+ @click.option(
92
+ "--resolve-dois",
93
+ "-r",
94
+ is_flag=True,
95
+ help="Attempt to resolve missing DOIs from metadata",
96
+ )
97
+ @click.option(
98
+ "--no-footnotes",
99
+ is_flag=True,
100
+ help="Disable references section (citations only)",
101
+ )
102
+ @click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
103
+ @click.option("--quiet", "-q", is_flag=True, help="Suppress non-essential output")
104
+ def docx(
105
+ manuscript_path: str | None,
106
+ resolve_dois: bool,
107
+ no_footnotes: bool,
108
+ verbose: bool,
109
+ quiet: bool,
110
+ ) -> None:
111
+ """Export manuscript to DOCX format for collaborative review.
112
+
113
+ Generates a Word document with numbered citations, embedded figures,
114
+ and a complete references section with DOI links. Output is automatically
115
+ saved to the manuscript directory with the same naming pattern as the PDF.
116
+
117
+ **MANUSCRIPT_PATH**: Directory containing manuscript files.
118
+ Defaults to MANUSCRIPT/
119
+
120
+ **Output**: Automatically saved to MANUSCRIPT/YEAR__lastname_et_al__rxiv.docx
121
+
122
+ ## Examples
123
+
124
+ **Basic export:**
125
+
126
+ $ rxiv docx
127
+
128
+ **Export from custom directory:**
129
+
130
+ $ rxiv docx MY_PAPER/
131
+
132
+ **With DOI resolution for missing entries:**
133
+
134
+ $ rxiv docx --resolve-dois
135
+
136
+ **Without references section (citations only):**
137
+
138
+ $ rxiv docx --no-footnotes
139
+ """
140
+ try:
141
+ # Configure logging
142
+ if verbose:
143
+ logger.set_level("DEBUG")
144
+ elif quiet:
145
+ logger.set_level("WARNING")
146
+
147
+ # Set manuscript path
148
+ manuscript_path = manuscript_path or "MANUSCRIPT"
149
+
150
+ # Create exporter
151
+ if not quiet:
152
+ console.print("[cyan]📄 Exporting manuscript to DOCX...[/cyan]")
153
+
154
+ exporter = DocxExporter(
155
+ manuscript_path=manuscript_path,
156
+ resolve_dois=resolve_dois,
157
+ include_footnotes=not no_footnotes,
158
+ )
159
+
160
+ # Pre-flight check for poppler (if manuscript contains PDF figures)
161
+ _check_and_offer_poppler_installation(console, quiet, verbose)
162
+
163
+ # Perform export
164
+ docx_path = exporter.export()
165
+
166
+ # Success message
167
+ if not quiet:
168
+ console.print(f"[green]✅ DOCX exported:[/green] {docx_path}")
169
+
170
+ except FileNotFoundError as e:
171
+ console.print(f"[red]❌ Error:[/red] {e}")
172
+ raise click.Abort() from e
173
+ except Exception as e:
174
+ if verbose:
175
+ logger.error(f"DOCX export failed: {e}")
176
+ console.print(f"[red]❌ Export failed:[/red] {e}")
177
+ raise click.Abort() from e
@@ -0,0 +1,52 @@
1
+ """Upgrade command for rxiv-maker CLI."""
2
+
3
+ import sys
4
+
5
+ import click
6
+ from henriqueslab_updater import handle_upgrade_workflow
7
+ from rich.console import Console
8
+
9
+ from ... import __version__
10
+ from ...utils.install_detector import detect_install_method
11
+ from ...utils.rich_upgrade_notifier import RxivUpgradeNotifier
12
+
13
+ console = Console()
14
+
15
+
16
+ @click.command()
17
+ @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
18
+ @click.option("--check-only", "-c", is_flag=True, help="Only check for updates, don't upgrade")
19
+ @click.pass_context
20
+ def upgrade(ctx: click.Context, yes: bool, check_only: bool) -> None:
21
+ """Upgrade rxiv-maker to the latest version.
22
+
23
+ This command automatically detects how rxiv-maker was installed
24
+ (Homebrew, pip, uv, pipx, etc.) and runs the appropriate upgrade command.
25
+
26
+ Examples:
27
+ rxiv upgrade # Check and upgrade with confirmation
28
+ rxiv upgrade --yes # Upgrade without confirmation
29
+ rxiv upgrade --check-only # Only check for updates
30
+ """
31
+ # Handle development installations specially
32
+ install_method = detect_install_method()
33
+ if install_method == "dev":
34
+ console.print("⚠️ Development installation detected", style="yellow")
35
+ console.print(" To update, pull the latest changes from git:", style="yellow")
36
+ console.print(" [cyan]cd <repo> && git pull && uv sync[/cyan]", style="yellow")
37
+ sys.exit(0)
38
+
39
+ # Use centralized upgrade workflow
40
+ notifier = RxivUpgradeNotifier(console)
41
+ success, error = handle_upgrade_workflow(
42
+ package_name="rxiv-maker",
43
+ current_version=__version__,
44
+ check_only=check_only,
45
+ skip_confirmation=yes,
46
+ notifier=notifier,
47
+ github_org="HenriquesLab",
48
+ github_repo="rxiv-maker",
49
+ )
50
+
51
+ if not success and error:
52
+ sys.exit(1)
@@ -487,6 +487,18 @@ class DependencyManager:
487
487
  )
488
488
  )
489
489
 
490
+ # Poppler utilities for PDF to image conversion (DOCX export)
491
+ self.register_dependency(
492
+ DependencySpec(
493
+ name="pdftoppm",
494
+ type=DependencyType.SYSTEM_BINARY,
495
+ required=False, # Only needed for DOCX export with PDF figures
496
+ alternatives=["pdfinfo"],
497
+ contexts={"docx", "export"},
498
+ install_hint="macOS: brew install poppler | Linux: sudo apt install poppler-utils",
499
+ )
500
+ )
501
+
490
502
  def register_dependency(self, spec: DependencySpec) -> None:
491
503
  """Register a dependency specification.
492
504
 
@@ -318,9 +318,13 @@ class DocxExporter:
318
318
  # Get DOI from entry
319
319
  doi = entry.fields.get("doi")
320
320
 
321
- # TODO: Implement DOI resolution if requested and DOI missing
322
- # if self.resolve_dois and not doi:
323
- # doi = self._resolve_doi_from_metadata(entry)
321
+ # Attempt DOI resolution if requested and DOI missing
322
+ if self.resolve_dois and not doi:
323
+ doi = self._resolve_doi_from_metadata(entry)
324
+ if doi:
325
+ # Store in entry for this export
326
+ entry.fields["doi"] = doi
327
+ logger.info(f"Resolved DOI for {key}: {doi}")
324
328
 
325
329
  # Format entry (full format for DOCX bibliography)
326
330
  formatted = format_bibliography_entry(entry, doi, slim=False, author_format=self.author_format)
@@ -332,6 +336,99 @@ class DocxExporter:
332
336
 
333
337
  return bibliography
334
338
 
339
+ def _resolve_doi_from_metadata(self, entry) -> str | None:
340
+ """Resolve DOI from entry metadata using CrossRef API.
341
+
342
+ Args:
343
+ entry: Bibliography entry to resolve DOI for
344
+
345
+ Returns:
346
+ Resolved DOI if found, None otherwise
347
+ """
348
+ import requests
349
+
350
+ # Try to construct a search query from available fields
351
+ title = entry.fields.get("title", "").strip()
352
+ year = entry.fields.get("year", "").strip()
353
+
354
+ if not title:
355
+ logger.debug(f"Cannot resolve DOI for {entry.key}: no title")
356
+ return None
357
+
358
+ # Clean title for search (remove LaTeX commands, braces, etc.)
359
+ search_title = self._clean_title_for_search(title)
360
+
361
+ # Try CrossRef search API
362
+ try:
363
+ url = "https://api.crossref.org/works"
364
+ params = {
365
+ "query.title": search_title,
366
+ "rows": 5, # Get top 5 results
367
+ }
368
+
369
+ response = requests.get(url, params=params, timeout=10)
370
+
371
+ if response.status_code == 200:
372
+ data = response.json()
373
+ items = data.get("message", {}).get("items", [])
374
+
375
+ # Find best match
376
+ for item in items:
377
+ item_title = item.get("title", [""])[0].lower()
378
+ search_title_lower = search_title.lower()
379
+
380
+ # Simple similarity check - titles should be very similar
381
+ if item_title and (search_title_lower in item_title or item_title in search_title_lower):
382
+ # Verify year matches if available
383
+ if year:
384
+ item_year = item.get("published", {}).get("date-parts", [[None]])[0][0]
385
+ if item_year and str(item_year) != year:
386
+ continue
387
+
388
+ doi = item.get("DOI")
389
+ if doi:
390
+ logger.info(f"Resolved DOI for {entry.key}: {doi}")
391
+ return doi
392
+
393
+ logger.debug(f"Could not resolve DOI for {entry.key} via CrossRef")
394
+ return None
395
+
396
+ except requests.exceptions.Timeout:
397
+ logger.debug(f"CrossRef API timeout resolving DOI for {entry.key}")
398
+ return None
399
+ except requests.exceptions.ConnectionError:
400
+ logger.debug(f"CrossRef API connection error for {entry.key}")
401
+ return None
402
+ except Exception as e:
403
+ logger.debug(f"Error resolving DOI for {entry.key}: {e}")
404
+ return None
405
+
406
+ def _clean_title_for_search(self, title: str) -> str:
407
+ """Clean title for CrossRef search by removing LaTeX commands.
408
+
409
+ Args:
410
+ title: Raw title from BibTeX entry
411
+
412
+ Returns:
413
+ Cleaned title suitable for search
414
+ """
415
+ import re
416
+
417
+ # Remove LaTeX commands
418
+ title = re.sub(r"\\[a-zA-Z]+\{([^}]*)\}", r"\1", title) # \textit{foo} -> foo
419
+ title = re.sub(r"\\[a-zA-Z]+", "", title) # \LaTeX -> LaTeX
420
+
421
+ # Remove braces
422
+ title = title.replace("{", "").replace("}", "")
423
+
424
+ # Remove special characters
425
+ title = re.sub(r"[^a-zA-Z0-9\s\-]", " ", title)
426
+
427
+ # Normalize whitespace
428
+ title = " ".join(title.split())
429
+
430
+ return title.strip()
431
+
335
432
  def _get_metadata(self) -> Dict[str, Any]:
336
433
  """Extract metadata for title page.
337
434
 
@@ -404,6 +404,19 @@ class DocxWriter:
404
404
  paragraph_format = paragraph.paragraph_format
405
405
  paragraph_format.left_indent = Pt(36) # Indent code blocks
406
406
 
407
+ def _check_poppler_availability(self) -> bool:
408
+ """Check if poppler is available for PDF conversion.
409
+
410
+ Returns:
411
+ True if poppler is available, False otherwise
412
+ """
413
+ from ..core.managers.dependency_manager import DependencyStatus, get_dependency_manager
414
+
415
+ manager = get_dependency_manager()
416
+ result = manager.check_dependency("pdftoppm")
417
+
418
+ return result.status == DependencyStatus.AVAILABLE
419
+
407
420
  def _add_figure(self, doc: Document, section: Dict[str, Any], figure_number: int = None):
408
421
  """Add figure to document with caption.
409
422
 
@@ -425,9 +438,31 @@ class DocxWriter:
425
438
  if not figure_path.exists():
426
439
  logger.warning(f"Figure file not found: {figure_path}")
427
440
  elif figure_path.suffix.lower() == ".pdf":
428
- # Convert PDF to image
429
- img_source = convert_pdf_to_image(figure_path)
430
- logger.debug(f" PDF converted: {img_source is not None}")
441
+ # Check poppler availability first (cached after first check)
442
+ if not hasattr(self, "_poppler_checked"):
443
+ self._poppler_available = self._check_poppler_availability()
444
+ self._poppler_checked = True
445
+
446
+ if not self._poppler_available:
447
+ logger.warning(
448
+ "Poppler not installed - PDF figures will be shown as placeholders. "
449
+ "Install with: brew install poppler (macOS) or sudo apt install poppler-utils (Linux)"
450
+ )
451
+
452
+ if self._poppler_available:
453
+ # Convert PDF to image
454
+ try:
455
+ from pdf2image.exceptions import PDFInfoNotInstalledError, PopplerNotInstalledError
456
+
457
+ img_source = convert_pdf_to_image(figure_path)
458
+ logger.debug(f" PDF converted: {img_source is not None}")
459
+ except (PopplerNotInstalledError, PDFInfoNotInstalledError) as e:
460
+ logger.error(f"Poppler utilities not found: {e}")
461
+ img_source = None
462
+ # Update our cached status
463
+ self._poppler_available = False
464
+ else:
465
+ img_source = None
431
466
  elif figure_path.suffix.lower() in [".png", ".jpg", ".jpeg", ".gif", ".bmp"]:
432
467
  # Use image file directly
433
468
  img_source = str(figure_path)
@@ -81,21 +81,41 @@ def generate_bst_file(format_type: str, output_dir: Path) -> Path:
81
81
  except IOError as e:
82
82
  raise IOError(f"Failed to read template .bst file: {e}") from e
83
83
 
84
- # Replace the format string on line 222
84
+ # Replace the format string in the format.names function (line ~222)
85
85
  # The line looks like: s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=
86
- # We need to replace the format string in quotes
87
- pattern = r'(s\s+nameptr\s+")([^"]+)("\s+format\.name\$)'
86
+ # We need to replace ONLY in format.names, NOT in format.full.names
87
+ #
88
+ # Strategy: Match the FUNCTION {format.names} block specifically
89
+ # This ensures we don't modify format.full.names which is used for citation labels
90
+ #
91
+ # Pattern explanation:
92
+ # 1. Match "FUNCTION {format.names}" to find the start of the function
93
+ # 2. Use non-greedy match (.*?) to capture until we find our target line
94
+ # 3. Match and capture the format string in quotes
95
+ # 4. This avoids matching format.full.names which appears later in the file
96
+ pattern = r'(FUNCTION\s+\{format\.names\}.*?s\s+nameptr\s+")([^"]+)("\s+format\.name\$)'
88
97
  replacement = rf"\1{format_string}\3"
89
98
 
90
- modified_content, num_subs = re.subn(pattern, replacement, bst_content)
99
+ modified_content, num_subs = re.subn(pattern, replacement, bst_content, flags=re.DOTALL)
91
100
 
92
101
  if num_subs == 0:
93
- logger.warning("No format string pattern found in .bst file. The .bst file may have been modified.")
102
+ logger.warning(
103
+ "No format string pattern found in format.names function. "
104
+ "The .bst file structure may have changed. "
105
+ "Citation formatting may not work as expected."
106
+ )
94
107
  # Still write the file but log a warning
95
108
  elif num_subs > 1:
96
- logger.warning(
97
- f"Found {num_subs} format string patterns in .bst file. Expected only 1. All have been replaced."
109
+ # This should never happen with the new pattern, but keep the check
110
+ logger.error(
111
+ f"Found {num_subs} matches in .bst file. Expected exactly 1. "
112
+ "This indicates an unexpected .bst file structure. "
113
+ "Please report this issue."
98
114
  )
115
+ raise ValueError(f"Unexpected .bst file structure: found {num_subs} matches for format.names, expected 1")
116
+ else:
117
+ # Success - exactly one match
118
+ logger.debug(f"Successfully updated format.names function with format '{format_type}'")
99
119
 
100
120
  # Create output directory if it doesn't exist
101
121
  output_dir = Path(output_dir)