psdi-data-conversion 0.1.7__tar.gz → 0.2.0__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 (155) hide show
  1. psdi_data_conversion-0.2.0/CHANGELOG.md +70 -0
  2. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/CONTRIBUTING.md +17 -15
  3. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/PKG-INFO +6 -2
  4. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/README.md +0 -1
  5. psdi_data_conversion-0.2.0/psdi_data_conversion/app.py +77 -0
  6. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/constants.py +11 -7
  7. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converter.py +41 -28
  8. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/base.py +18 -13
  9. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/database.py +284 -88
  10. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/__init__.py +5 -0
  11. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/accessibility.py +51 -0
  12. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/env.py +239 -0
  13. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/get.py +53 -0
  14. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/post.py +176 -0
  15. psdi_data_conversion-0.2.0/psdi_data_conversion/gui/setup.py +102 -0
  16. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/main.py +70 -13
  17. psdi_data_conversion-0.2.0/psdi_data_conversion/static/content/convert.htm +172 -0
  18. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/convertato.htm +36 -26
  19. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/convertc2x.htm +39 -26
  20. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/download.htm +5 -5
  21. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/feedback.htm +2 -2
  22. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/header-links.html +2 -2
  23. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/header-links.html +2 -2
  24. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/psdi-common-header.html +9 -12
  25. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/psdi-common-header.html +9 -12
  26. psdi_data_conversion-0.2.0/psdi_data_conversion/static/javascript/accessibility.js +223 -0
  27. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/data.js +1 -3
  28. psdi_data_conversion-0.2.0/psdi_data_conversion/static/javascript/load_accessibility.js +106 -0
  29. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/styles/format.css +72 -18
  30. psdi_data_conversion-0.2.0/psdi_data_conversion/templates/accessibility.htm +274 -0
  31. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/templates/documentation.htm +6 -6
  32. psdi_data_conversion-0.2.0/psdi_data_conversion/templates/index.htm +151 -0
  33. {psdi_data_conversion-0.1.7/psdi_data_conversion/static/content → psdi_data_conversion-0.2.0/psdi_data_conversion/templates}/report.htm +28 -10
  34. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/conversion_test_specs.py +26 -6
  35. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/utils.py +6 -6
  36. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/pyproject.toml +9 -3
  37. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/gui/gui_test.py +8 -3
  38. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/cli_test.py +48 -9
  39. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/database_test.py +35 -4
  40. psdi_data_conversion-0.1.7/CHANGELOG.md +0 -34
  41. psdi_data_conversion-0.1.7/psdi_data_conversion/app.py +0 -480
  42. psdi_data_conversion-0.1.7/psdi_data_conversion/static/content/accessibility.htm +0 -255
  43. psdi_data_conversion-0.1.7/psdi_data_conversion/static/content/convert.htm +0 -141
  44. psdi_data_conversion-0.1.7/psdi_data_conversion/static/javascript/accessibility.js +0 -196
  45. psdi_data_conversion-0.1.7/psdi_data_conversion/static/javascript/load_accessibility.js +0 -89
  46. psdi_data_conversion-0.1.7/psdi_data_conversion/templates/index.htm +0 -134
  47. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/.gitignore +0 -0
  48. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/LICENSE +0 -0
  49. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/__init__.py +0 -0
  50. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/LICENSE_ATOMSK +0 -0
  51. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/LICENSE_C2X +0 -0
  52. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/linux/atomsk +0 -0
  53. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/linux/c2x +0 -0
  54. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/mac/atomsk +0 -0
  55. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/mac/c2x +0 -0
  56. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/__init__.py +0 -0
  57. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/atomsk.py +0 -0
  58. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/c2x.py +0 -0
  59. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/openbabel.py +0 -0
  60. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/dist.py +0 -0
  61. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/file_io.py +0 -0
  62. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/log_utility.py +0 -0
  63. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/scripts/atomsk.sh +0 -0
  64. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/scripts/c2x.sh +0 -0
  65. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/security.py +0 -0
  66. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/psdi-common-footer.html +0 -0
  67. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/psdi-common-footer.html +0 -0
  68. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/data/data.json +0 -0
  69. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/colormode-toggle-dm.svg +0 -0
  70. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/colormode-toggle-lm.svg +0 -0
  71. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-icon-dark.svg +0 -0
  72. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-icon-light.svg +0 -0
  73. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-darktext-simple.png +0 -0
  74. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-darktext.png +0 -0
  75. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-lighttext-simple.png +0 -0
  76. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-lighttext.png +0 -0
  77. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-bluesky-black.svg +0 -0
  78. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-bluesky-white.svg +0 -0
  79. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-instagram-black.svg +0 -0
  80. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-instagram-white.svg +0 -0
  81. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-linkedin-black.png +0 -0
  82. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-linkedin-white.png +0 -0
  83. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-mastodon-black.svg +0 -0
  84. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-mastodon-white.svg +0 -0
  85. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-x-black.svg +0 -0
  86. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-x-white.svg +0 -0
  87. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-youtube-black.png +0 -0
  88. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-youtube-white.png +0 -0
  89. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-epsr-logo-darktext.png +0 -0
  90. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-epsr-logo-lighttext.png +0 -0
  91. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-logo-darktext.png +0 -0
  92. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-logo-lighttext.png +0 -0
  93. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/common.js +0 -0
  94. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convert.js +0 -0
  95. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convert_common.js +0 -0
  96. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convertato.js +0 -0
  97. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convertc2x.js +0 -0
  98. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/format.js +0 -0
  99. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/psdi-common.js +0 -0
  100. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/report.js +0 -0
  101. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/styles/psdi-common.css +0 -0
  102. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/__init__.py +0 -0
  103. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/constants.py +0 -0
  104. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/conversion_callbacks.py +0 -0
  105. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/gui.py +0 -0
  106. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/psdi_data_conversion/utils.py +0 -0
  107. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/scripts/setup_bin.py +0 -0
  108. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/1ARJ.mmcif +0 -0
  109. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/1NE6.mmcif +0 -0
  110. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/5a9z-assembly1.cif +0 -0
  111. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/Fapatite.ins +0 -0
  112. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/aceticacid.mol +0 -0
  113. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/benzyne.molden +0 -0
  114. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.tar +0 -0
  115. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.tar.gz +0 -0
  116. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.zip +0 -0
  117. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/caffeine.inchi +0 -0
  118. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/ch3cl-esp.cub +0 -0
  119. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/cyclopropane_err.mol +0 -0
  120. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/ethanol.xyz +0 -0
  121. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/fullRhinovirus.pdb +0 -0
  122. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/hemoglobin.pdb +0 -0
  123. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/nacl.cif +0 -0
  124. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/nacl.mol +0 -0
  125. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/aceticacid.log.txt +0 -0
  126. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/aceticacid.mol2 +0 -0
  127. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine-2D-fastest.xyz +0 -0
  128. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine-3D-best.xyz +0 -0
  129. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine.smi +0 -0
  130. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine.xyz +0 -0
  131. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in.smi +0 -0
  132. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_f4_l5_out.smi +0 -0
  133. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_f4_out.smi +0 -0
  134. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_out.smi +0 -0
  135. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_x_out.smi +0 -0
  136. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/hemoglobin_Atomsk.xyz +0 -0
  137. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/hemoglobin_c2x.xyz +0 -0
  138. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/nacl.log +0 -0
  139. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/nacl.mol +0 -0
  140. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/quartz_OB.cif +0 -0
  141. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/quartz_OB.log.txt +0 -0
  142. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/quartz_atomsk.cif +0 -0
  143. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/quartz_atomsk.log.txt +0 -0
  144. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/standard_test.inchi +0 -0
  145. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/xyz_files-mol.zip +0 -0
  146. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/output/xyz_files.log.txt +0 -0
  147. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/periodic_dmol3.outmol +0 -0
  148. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/quartz.xyz +0 -0
  149. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/quartz_err.xyz +0 -0
  150. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/test_data/standard_test.cdxml +0 -0
  151. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/converter_test.py +0 -0
  152. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/dist_test.py +0 -0
  153. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/file_io_test.py +0 -0
  154. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/logging_test.py +0 -0
  155. {psdi_data_conversion-0.1.7 → psdi_data_conversion-0.2.0}/tests/python/security_test.py +0 -0
@@ -0,0 +1,70 @@
1
+ # Changelog for PSDI Data Conversion
2
+
3
+ ## v0.2.0
4
+
5
+ ### New and Changed Functionality
6
+
7
+ - Changed the keyword arguments `upload_dir` and `download_dir` to `input_dir` and `output_dir` respectively
8
+ - Formats can now be specified case-insensitively
9
+ - When requesting details on a format through the command-line interface, details will be provided on which molecular properties it supports (e.g. whether or not it supports connections information)
10
+ - Added function `database.get_conversion_pathway` which can be used to get possible conversion routes between formats a direct conversion isn't possible with any converter
11
+ - When requesting details on two formats through the command-line interface and a direct conversion between them is not possible, a possible chain conversion will now be recommended
12
+
13
+ ### Bugfixes
14
+
15
+ - Fixed bug where the `input_dir` keyword argument for `run_converter` was being ignored
16
+ - Fixed bug where the local-mode-only text was incorrectly appearing on the report page in service mode
17
+
18
+ ### Testing Changes
19
+
20
+ - Excluded GUI modules from the calculating unit test coverage which can't be measured by the tool
21
+ - Added automated test that the production deployment is working on a schedule and after deploying to it
22
+
23
+ ### Documentation Changes
24
+
25
+ - The Documentation page of the GUI now shows the mode that's being run, the most recent tag, and the SHA of the most recent commit (if this isn't the latest tagged commit)
26
+ - Updated release procedure and checklist in `CONTRIBUTING.md` to reflect current procedure
27
+
28
+ ### Formatting and Refactoring Changes
29
+
30
+ - Changed Documentation and Accessibility pages of the GUI to work as Flask templates
31
+ - Cleaned up Flask files to not be all in one module
32
+ - Changed the database functionality to store possible conversions as a graph instead of a table
33
+ - Dockerfile now builds from `pyproject.toml`, with the now-unused `requirements.txt` removed
34
+
35
+ ### Stylistic Changes
36
+
37
+ - Reformatted pages of the GUI/web app to use a two panel display, with instructions for components in boxes alongside them
38
+
39
+ ## v0.1.7
40
+
41
+ ### New and Changed Functionality
42
+
43
+ - Version, SHA, and service/prod modes now always shown in new About section on the Documentation page
44
+
45
+ ### Documentation Changes
46
+
47
+ - Added information about deployment to CONTRIBUTING.md
48
+
49
+ ### Bugfixes
50
+
51
+ - Environmental variable indicating dev or production mode should now be properly set for the deployed service
52
+
53
+ ## v0.1.6
54
+
55
+ ### New and Changed Functionality
56
+
57
+ - SHA banner at the bottom of home page now preferentially shows the version, only showing the SHA if the current version doesn't match the last tag
58
+
59
+ ### Bugfixes
60
+
61
+ - Fixed bug which was blocking deployment to production
62
+
63
+ ## v0.1.0
64
+
65
+ Initial public release. Features included:
66
+
67
+ - Online server functionality
68
+ - Locally-hosted server
69
+ - Command-line interface
70
+ - Python library
@@ -21,7 +21,7 @@ The following tasks should be completed before merging a release candidate branc
21
21
  - Otherwise, if any features are added, or any breaking changes are made before version 1.0.0, the version will advance to the next minor version - `X.Y.Z` to `X.(Y+1).0`.
22
22
  - Otherwise, the version will advance to the next bugfix version - `X.Y.Z` to `X.Y.(Z+1)`.
23
23
 
24
- - Create a release candidate branch with the name `rc-<target-version>` (e.g. `rc-1.2.3`). This should trigger an automated workflow to create a Pull Request from this branch to`release`. You may wish to edit the PR's name and/or description.
24
+ - Create a release candidate branch with the name `rc-<target-version>` (e.g. `rc-1.2.3`), branched off of `main`. This should trigger an automated workflow to create a Pull Request from this branch to `release`. You may wish to edit the PR's name and/or description.
25
25
 
26
26
  - Tagging of the release is handled by an automated workflow which determines the new version based on the previous version and the commit history, looking for any commits which indicate a feature addition or breaking change using [Angular convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular#commit-message-format). Since we don't practice this regularly, you'll need to make a commit with this style to indicate any feature additions or breaking changes (this can be done when updating the version in the next step):
27
27
 
@@ -53,7 +53,7 @@ The following tasks should be completed before merging a release candidate branc
53
53
 
54
54
  - Ensure that all automated tests and checks pass - these should be run automatically on the PR opened above
55
55
 
56
- - Manually test the local web interface
56
+ - Manually test the web interface. At this stage, it should be deployed to dev at https://data-conversion-dev.psdi.ac.uk/ (requires VPN to access), and it can be run locally as well
57
57
 
58
58
  - If there have been any changes to the Python backend, run a test that a file can be converted successfully and produces a proper log
59
59
  - If there have been any changes to the web frontend, check the appearance of the site to ensure that it looks as desired. Test the Accessibility page to ensure that changes there work properly, are saved when requested and apply to other pages
@@ -65,7 +65,10 @@ If any of these tasks fail and require changes, make the needed changes and then
65
65
  Then, follow the following steps to make the release:
66
66
 
67
67
  1. Merge the pull request to `release`. The release candidate branch can be safely deleted. This should trigger an automated pipeline to tag, publish, and deploy and the new code.
68
- 2. Merge `release` into `main` via PR (obviously don't delete `release` - if it even gives you the option to, something has gone wrong in the project rulesets, so report this).
68
+ 2. After the above pipeline finishes, confirm that the changes are shown live on the staging site at https://data-conversion-staging.psdi.ac.uk/ by checking the version shown at the bottom of the Documentation page. If necessary, double-check that nothing has broken due to the slight changes in appearance between the dev and staging sites
69
+ 3. Manually trigger the `CI - Deploy to production cluster` workflow on the `release` branch to deploy the site from the staging to release environment, which will make the changes visible to users
70
+ 4. After completion of the workflow, confirm that the changes are live on the production site at https://data-conversion.psdi.ac.uk/ by checking the version shown at the bottom of the Documentation page
71
+ 5. Merge `release` into `main` via PR (obviously don't delete `release` - if it even gives you the option to, something has gone wrong in the project rulesets, so report this).
69
72
 
70
73
  ## Changelog
71
74
 
@@ -377,10 +380,11 @@ The management page can also be used to add or remove collaborators through the
377
380
  ## Deployment
378
381
 
379
382
  The `ci-main.yml`, `ci-release.yml` and `ci-deploy-production.yml` files in the `.github/workflows` directory house workflows which deploy
380
- the data conversion service to [Kubernetes](https://kubernetes.io/) clusters hosted in STFC. There are three clusters, each of which correspond
383
+ the data conversion service to [Kubernetes](https://kubernetes.io/) clusters hosted in STFC. There are three clusters, each of which correspond
381
384
  to a different deployment _environment_ for the data conversion service. The three environments are `development`, `staging` and `production`.
382
385
  Deployment to `development`, `staging` and `production` is done from either the `main` or `release` branch. The table below indicates which
383
386
  branch deploys to which environment. The table also shows, for each environment:
387
+
384
388
  - the URL on which the service is exposed once it is successfully deployed
385
389
  - the accessibility of the service. Depending on the environment the service is either accessible to the _public_ at the specified URL,
386
390
  or accessible only to IP addresses within the _STFC and University of Southampton subnets_
@@ -388,11 +392,11 @@ branch deploys to which environment. The table also shows, for each environment:
388
392
  upon a commit to the source branch which passes the unit-tests job; or results from a _manual_ invocation of a workflow by a
389
393
  developer.
390
394
 
391
- | Environment | URL | Accessibility | Source branch | Deployment trigger |
392
- |------------------|--------------------------------------------|--------------------------------------------|----------------|-----------------------|
393
- | `development` | https://data-conversion-dev.psdi.ac.uk | STFC and University of Southampton subnets | `main` | Automatic |
394
- | `staging` | https://data-conversion-staging.psdi.ac.uk | STFC and University of Southampton subnets | `release` | Automatic |
395
- | `production` | https://data-conversion.psdi.ac.uk | public | `release` | Manual |
395
+ | Environment | URL | Accessibility | Source branch | Deployment trigger |
396
+ | ------------- | ------------------------------------------ | ------------------------------------------ | ------------- | ------------------ |
397
+ | `development` | https://data-conversion-dev.psdi.ac.uk | STFC and University of Southampton subnets | `main` | Automatic |
398
+ | `staging` | https://data-conversion-staging.psdi.ac.uk | STFC and University of Southampton subnets | `release` | Automatic |
399
+ | `production` | https://data-conversion.psdi.ac.uk | public | `release` | Manual |
396
400
 
397
401
  Thus the `main` is automatically deployed to the `development` environment, and the `release` branch is automatically deployed to the `staging`
398
402
  environment. However deployment from the `release` branch to the `production` environment is a manual process. This is to allow developers to
@@ -416,7 +420,7 @@ listed on the left named `CI - Deploy to production cluster`. This is the workfl
416
420
  version to the `production` environment. Clicking on the link to this workflow gives
417
421
  [a list of recent invocations](https://github.com/PSDI-UK/psdi-data-conversion/actions/workflows/ci-deploy-production.yml) of the workflow.
418
422
  Moreover, a light blue banner appears which says `This workflow has a workflow_dispatch event trigger` on the left and has a `Run workflow` button
419
- on the right. To invoke the workflow, press this button, *select the `release` branch* as the option for `Use workflow from` dropdown menu, and
423
+ on the right. To invoke the workflow, press this button, _select the `release` branch_ as the option for `Use workflow from` dropdown menu, and
420
424
  then finally click the green `Run workflow` button. Once the workflow has been invoked you should be able to see its progress in real time on the
421
425
  same page.
422
426
 
@@ -431,13 +435,11 @@ the `<env>` environment using the Kubernetes manifests stored in the `deploy`/<e
431
435
 
432
436
  The workflow relies on several repository secrets, namely `KUBECONF`, `IMAGEPULLSECRET`, `CERTIFICATE_PRIVATE_KEY` and `CERTIFICATE_PEM` for
433
437
  various purposes.
438
+
434
439
  - `KUBECONF` provides Kubernetes-specific information pertaining to the the Kubernetes cluster for the target environment. Note that
435
- `KUBECONF` is an _environment_-dependent secret, taking different values for each of the environments.
440
+ `KUBECONF` is an _environment_-dependent secret, taking different values for each of the environments.
436
441
  - `IMAGEPULLSECRET` enables the container image housing the data conversion service to be pulled from this GitHub repo to the PSDI runner
437
442
  - `CERTIFICATE_PRIVATE_KEY` and `CERTIFICATE_PEM` pertain to the TLS certificates for the service
438
- For further information see the `job-deploy-k8s.yml` file and aforementioned Kubernetes manifests.
439
-
440
-
441
-
443
+ For further information see the `job-deploy-k8s.yml` file and aforementioned Kubernetes manifests.
442
444
 
443
445
  The server can be configured by editing the environmental variables set in `Dockerfile`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psdi_data_conversion
3
- Version: 0.1.7
3
+ Version: 0.2.0
4
4
  Summary: Chemistry file format conversion service, provided by PSDI
5
5
  Project-URL: Homepage, https://data-conversion.psdi.ac.uk/
6
6
  Project-URL: Documentation, https://psdi-uk.github.io/psdi-data-conversion/
@@ -222,8 +222,13 @@ Classifier: Programming Language :: Python :: 3
222
222
  Classifier: Topic :: File Formats
223
223
  Classifier: Topic :: Scientific/Engineering :: Chemistry
224
224
  Requires-Python: >=3.12
225
+ Requires-Dist: igraph
225
226
  Requires-Dist: openbabel-wheel
226
227
  Requires-Dist: py
228
+ Provides-Extra: deploy
229
+ Requires-Dist: flask; extra == 'deploy'
230
+ Requires-Dist: gunicorn; extra == 'deploy'
231
+ Requires-Dist: requests; extra == 'deploy'
227
232
  Provides-Extra: doc
228
233
  Requires-Dist: pdoc3; extra == 'doc'
229
234
  Provides-Extra: gui
@@ -330,7 +335,6 @@ This is the repository for the PSDI PF2 Chemistry File Format Conversion project
330
335
  - `LICENSE` (Apache License version 2.0)
331
336
  - `pyproject.toml` (Python project metadata and settings)
332
337
  - `README.md` (This file)
333
- - `requirements.txt` (Requirements for the web app deployment of this project)
334
338
 
335
339
  ## Requirements
336
340
 
@@ -87,7 +87,6 @@ This is the repository for the PSDI PF2 Chemistry File Format Conversion project
87
87
  - `LICENSE` (Apache License version 2.0)
88
88
  - `pyproject.toml` (Python project metadata and settings)
89
89
  - `README.md` (This file)
90
- - `requirements.txt` (Requirements for the web app deployment of this project)
91
90
 
92
91
  ## Requirements
93
92
 
@@ -0,0 +1,77 @@
1
+ """app.py
2
+
3
+ Version 1.0, 8th November 2024
4
+
5
+ This script acts as a server for the PSDI Data Conversion Service website.
6
+ """
7
+
8
+ from argparse import ArgumentParser
9
+
10
+ from psdi_data_conversion import constants as const
11
+ from psdi_data_conversion.gui.env import update_env
12
+ from psdi_data_conversion.gui.setup import get_app, limit_upload_size, start_app
13
+ from psdi_data_conversion.main import print_wrap
14
+
15
+ app = get_app()
16
+
17
+
18
+ def main():
19
+ """Standard entry-point function for this script.
20
+ """
21
+
22
+ parser = ArgumentParser()
23
+
24
+ parser.add_argument("--use-env-vars", action="store_true",
25
+ help="If set, all other arguments and defaults for this script are ignored, and environmental "
26
+ "variables and their defaults will instead control execution. These defaults will result in "
27
+ "the app running in production server mode.")
28
+
29
+ parser.add_argument("--max-file-size", type=float, default=const.DEFAULT_MAX_FILE_SIZE/const.MEGABYTE,
30
+ help="The maximum allowed filesize in MB - 0 (default) indicates no maximum")
31
+
32
+ parser.add_argument("--max-file-size-ob", type=float, default=const.DEFAULT_MAX_FILE_SIZE_OB/const.MEGABYTE,
33
+ help="The maximum allowed filesize in MB for the Open Babel converter, taking precendence over "
34
+ "the general maximum file size when Open Babel is used - 0 indicates no maximum. Default 1 MB.")
35
+
36
+ parser.add_argument("--service-mode", action="store_true",
37
+ help="If set, will run as if deploying a service rather than the local GUI")
38
+
39
+ parser.add_argument("--dev-mode", action="store_true",
40
+ help="If set, will expose development elements, such as the SHA of the latest commit")
41
+
42
+ parser.add_argument("--debug", action="store_true",
43
+ help="If set, will run the Flask server in debug mode, which will cause it to automatically "
44
+ "reload if code changes and show an interactive debugger in the case of errors")
45
+
46
+ parser.add_argument("--log-mode", type=str, default=const.LOG_FULL,
47
+ help="How logs should be stored. Allowed values are: \n"
48
+ "- 'full' - Multi-file logging, not recommended for the CLI, but allowed for a compatible "
49
+ "interface with the public web app"
50
+ "- 'simple' - Logs saved to one file"
51
+ "- 'stdout' - Output logs and errors only to stdout"
52
+ "- 'none' - Output only errors to stdout")
53
+
54
+ parser.add_argument("--log-level", type=str, default=None,
55
+ help="The desired level to log at. Allowed values are: 'DEBUG', 'INFO', 'WARNING', 'ERROR, "
56
+ "'CRITICAL'. Default: 'INFO' for logging to file, 'WARNING' for logging to stdout")
57
+
58
+ # Set global variables for settings based on parsed arguments, unless it's set to use env vars
59
+ args = parser.parse_args()
60
+
61
+ if not args.use_env_vars:
62
+ # Overwrite the values from environmental variables with the values from the command-line arguments
63
+ update_env(args)
64
+
65
+ # Set the upload limit based on provided arguments now
66
+ limit_upload_size()
67
+
68
+ print_wrap("Starting the PSDI Data Conversion GUI. This GUI is run as a webpage, which you can open by "
69
+ "right-clicking the link below to open it in your default browser, or by copy-and-pasting it into your "
70
+ "browser of choice.")
71
+
72
+ start_app()
73
+
74
+
75
+ if __name__ == "__main__":
76
+
77
+ main()
@@ -36,6 +36,9 @@ import shutil
36
36
  # The name of the command-line script
37
37
  CL_SCRIPT_NAME = "psdi-data-convert"
38
38
 
39
+ # The name of the Flask app
40
+ APP_NAME = "psdi_data_conversion"
41
+
39
42
  # Environmental variables
40
43
  LOG_MODE_EV = "LOG_MODE"
41
44
  LOG_LEVEL_EV = "LOG_LEVEL"
@@ -52,8 +55,8 @@ MEGABYTE = 1024*1024
52
55
  DEFAULT_MAX_FILE_SIZE = 0 * MEGABYTE
53
56
  DEFAULT_MAX_FILE_SIZE_OB = 1 * MEGABYTE
54
57
 
55
- DEFAULT_UPLOAD_DIR = './psdi_data_conversion/static/uploads'
56
- DEFAULT_DOWNLOAD_DIR = './psdi_data_conversion/static/downloads'
58
+ DEFAULT_INPUT_DIR = './psdi_data_conversion/static/uploads'
59
+ DEFAULT_OUTPUT_DIR = './psdi_data_conversion/static/downloads'
57
60
 
58
61
  # Filename of the database, relative to the base of the python package
59
62
  DATABASE_FILENAME = "static/data/data.json"
@@ -150,11 +153,6 @@ QUAL_2D_LABEL = "2D atomic coordinates are"
150
153
  QUAL_3D_KEY = "three_dim"
151
154
  QUAL_3D_LABEL = "2D atomic coordinates are"
152
155
 
153
- D_QUAL_LABELS = {QUAL_COMP_KEY: QUAL_COMP_LABEL,
154
- QUAL_CONN_KEY: QUAL_CONN_LABEL,
155
- QUAL_2D_KEY: QUAL_2D_LABEL,
156
- QUAL_3D_KEY: QUAL_3D_LABEL}
157
-
158
156
  # Notes for conversion quality
159
157
  QUAL_NOTE_IN_UNKNOWN = ("Potential data extrapolation: {} represented in the output format but its representation in "
160
158
  "the input format is unknown")
@@ -187,3 +185,9 @@ ERR_WRONG_EXTENSIONS = "Input file '{file}' does not have expected extension '{e
187
185
  ERR_EMPTY_ARCHIVE = "No files to convert were contained in archive"
188
186
  ERR_CONVERSION_FAILED = ("File conversion failed for one or more files. Lines from the output log "
189
187
  "{} which indicate possible sources of error: ")
188
+
189
+ # Misc
190
+ # ----
191
+
192
+ # Year in seconds
193
+ YEAR = 365*24*60*60
@@ -5,22 +5,20 @@ Created 2024-12-10 by Bryan Gillis.
5
5
  Class and functions to perform file conversion
6
6
  """
7
7
 
8
- from dataclasses import dataclass, field
9
- import json
10
8
  import glob
11
9
  import importlib
10
+ import json
12
11
  import os
13
12
  import sys
14
13
  import traceback
15
- from typing import Any, Callable, NamedTuple
16
- from multiprocessing import Lock
17
- from psdi_data_conversion import log_utility
18
14
  from collections.abc import Callable
19
15
  from dataclasses import dataclass, field
16
+ from multiprocessing import Lock
20
17
  from tempfile import TemporaryDirectory
21
18
  from typing import Any, NamedTuple
22
19
 
23
20
  from psdi_data_conversion import constants as const
21
+ from psdi_data_conversion import log_utility
24
22
  from psdi_data_conversion.converters import base
25
23
  from psdi_data_conversion.converters.openbabel import CONVERTER_OB
26
24
  from psdi_data_conversion.file_io import (is_archive, is_supported_archive, pack_zip_or_tar, split_archive_ext,
@@ -184,9 +182,9 @@ def get_converter(*args, name=const.CONVERTER_DEFAULT, **converter_kwargs) -> ba
184
182
  use_envvars : bool
185
183
  If set to True, environment variables will be checked for any that set options for this class and used,
186
184
  default False
187
- upload_dir : str
185
+ input_dir : str
188
186
  The location of input files relative to the current directory
189
- download_dir : str
187
+ output_dir : str
190
188
  The location of output files relative to the current directory
191
189
  max_file_size : float
192
190
  The maximum allowed file size for input/output files, in MB, default 1 MB for Open Babel, unlimited for other
@@ -315,11 +313,18 @@ def check_from_format(filename: str,
315
313
  return False
316
314
 
317
315
 
316
+ def _run_single_file_conversion(*args, **kwargs):
317
+ """Run a conversion on a single file, after all arguments have been checked
318
+ """
319
+ return get_converter(*args, **kwargs).run()
320
+
321
+
318
322
  def run_converter(filename: str,
319
323
  to_format: str,
320
324
  *args,
321
325
  from_format: str | None = None,
322
- download_dir=const.DEFAULT_DOWNLOAD_DIR,
326
+ input_dir=const.DEFAULT_INPUT_DIR,
327
+ output_dir=const.DEFAULT_OUTPUT_DIR,
323
328
  max_file_size=None,
324
329
  log_file: str | None = None,
325
330
  log_mode=const.LOG_SIMPLE,
@@ -351,9 +356,9 @@ def run_converter(filename: str,
351
356
  use_envvars : bool
352
357
  If set to True, environment variables will be checked for any that set options for this class and used,
353
358
  default False
354
- upload_dir : str
359
+ input_dir : str
355
360
  The location of input files relative to the current directory
356
- download_dir : str
361
+ output_dir : str
357
362
  The location of output files relative to the current directory
358
363
  strict : bool
359
364
  If True and `from_format` is not None, will fail if any input file has the wrong extension (including files
@@ -410,7 +415,12 @@ def run_converter(filename: str,
410
415
  # converter class, so it needs to be set up here to match what will be set up there
411
416
  if log_file is None:
412
417
  base_filename = os.path.basename(split_archive_ext(filename)[0])
413
- log_file = os.path.join(download_dir, base_filename + const.OUTPUT_LOG_EXT)
418
+ log_file = os.path.join(output_dir, base_filename + const.OUTPUT_LOG_EXT)
419
+
420
+ if os.path.exists(filename):
421
+ qualified_filename = filename
422
+ else:
423
+ qualified_filename = os.path.join(input_dir, filename)
414
424
 
415
425
  # Check if the filename is for an archive file, and handle appropriately
416
426
 
@@ -425,15 +435,16 @@ def run_converter(filename: str,
425
435
  # Not an archive, so just get and run the converter straightforwardly
426
436
  if from_format is not None:
427
437
  check_from_format(filename, from_format, strict=strict)
428
- l_run_output.append(get_converter(filename,
438
+ l_run_output.append(_run_single_file_conversion(filename,
429
439
  to_format,
430
440
  *args,
431
441
  from_format=from_format,
432
- download_dir=download_dir,
442
+ input_dir=input_dir,
443
+ output_dir=output_dir,
433
444
  max_file_size=max_file_size,
434
445
  log_file=log_file,
435
446
  log_mode=log_mode,
436
- **converter_kwargs).run())
447
+ **converter_kwargs))
437
448
 
438
449
  elif not is_supported_archive(filename):
439
450
  raise base.FileConverterInputException(f"{filename} is an unsupported archive type. Supported types are: "
@@ -443,7 +454,7 @@ def run_converter(filename: str,
443
454
  # The filename is of a supported archive type. Make a temporary directory to extract its contents
444
455
  # to, then run the converter on each file extracted
445
456
  with TemporaryDirectory() as extract_dir:
446
- l_filenames = unpack_zip_or_tar(filename, extract_dir=extract_dir)
457
+ l_filenames = unpack_zip_or_tar(qualified_filename, extract_dir=extract_dir)
447
458
 
448
459
  # Check for no files in archive
449
460
  if len(l_filenames) == 0:
@@ -468,15 +479,15 @@ def run_converter(filename: str,
468
479
  individual_log_mode = log_mode if log_mode != const.LOG_FULL else const.LOG_FULL_FORCE
469
480
 
470
481
  try:
471
- individual_run_output = get_converter(extracted_filename,
472
- to_format,
473
- *args,
474
- from_format=from_format,
475
- download_dir=download_dir,
476
- log_file=individual_log_file,
477
- log_mode=individual_log_mode,
478
- max_file_size=remaining_file_size,
479
- **converter_kwargs).run()
482
+ individual_run_output = _run_single_file_conversion(extracted_filename,
483
+ to_format,
484
+ *args,
485
+ from_format=from_format,
486
+ output_dir=output_dir,
487
+ log_file=individual_log_file,
488
+ log_mode=individual_log_mode,
489
+ max_file_size=remaining_file_size,
490
+ **converter_kwargs)
480
491
  except base.FileConverterAbortException as e:
481
492
  # If the run fails, create a run output object to indicate that
482
493
  individual_run_output = base.FileConversionResult(log_filename=individual_log_file,
@@ -573,12 +584,13 @@ def run_converter(filename: str,
573
584
  "input_filename": in_filename,
574
585
  "output_filename": run_output.output_filename[l_index:r_index],
575
586
  "input_size": input_size,
576
- "output_size": output_size }
587
+ "output_size": output_size}
577
588
 
578
- for key in [ "converter", "coordinates", "coordOption", "from_flags",
579
- "to_flags", "from_arg_flags", "to_arg_flags" ]:
589
+ for key in ["converter", "coordinates", "coordOption", "from_flags",
590
+ "to_flags", "from_arg_flags", "to_arg_flags"]:
580
591
  if key in converter_kwargs['data'] and converter_kwargs['data'][key] != "" and not \
581
- ((key == "coordinates" or key == "coordOption") and converter_kwargs['data']['coordinates'] == "neither") :
592
+ ((key == "coordinates" or key == "coordOption") and
593
+ converter_kwargs['data']['coordinates'] == "neither"):
582
594
  entry[key] = converter_kwargs['data'][key]
583
595
 
584
596
  entry["outcome"] = outcome
@@ -595,6 +607,7 @@ def run_converter(filename: str,
595
607
 
596
608
  return run_output
597
609
 
610
+
598
611
  def set_size_units(size):
599
612
  if size >= 1024:
600
613
  return str('%.3f' % (size / 1024)) + ' kB'
@@ -206,8 +206,8 @@ class FileConverter:
206
206
  data: dict[str, Any] | None = None,
207
207
  abort_callback: Callable[[int], None] = abort_raise,
208
208
  use_envvars=False,
209
- upload_dir=const.DEFAULT_UPLOAD_DIR,
210
- download_dir=const.DEFAULT_DOWNLOAD_DIR,
209
+ input_dir=const.DEFAULT_INPUT_DIR,
210
+ output_dir=const.DEFAULT_OUTPUT_DIR,
211
211
  max_file_size=None,
212
212
  no_check=False,
213
213
  log_file: str | None = None,
@@ -235,9 +235,9 @@ class FileConverter:
235
235
  use_envvars : bool
236
236
  If set to True, environment variables will be checked for any that set options for this class and used,
237
237
  default False
238
- upload_dir : str
238
+ input_dir : str
239
239
  The location of input files relative to the current directory
240
- download_dir : str
240
+ output_dir : str
241
241
  The location of output files relative to the current directory
242
242
  max_file_size : float
243
243
  The maximum allowed file size for input/output files, in MB. If 0, will be unlimited. Default 0 (unlimited)
@@ -296,8 +296,8 @@ class FileConverter:
296
296
  # Set member variables directly from input
297
297
  self.in_filename = filename
298
298
  self.to_format = to_format
299
- self.upload_dir = upload_dir
300
- self.download_dir = download_dir
299
+ self.input_dir = input_dir
300
+ self.output_dir = output_dir
301
301
  self.log_file = log_file
302
302
  self.log_mode = log_mode
303
303
  self.log_level = log_level
@@ -328,17 +328,22 @@ class FileConverter:
328
328
  self.err: str | None = None
329
329
  self.quality: str | None = None
330
330
 
331
- # Create directory 'uploads' if not extant.
332
- if not os.path.exists(self.upload_dir):
333
- os.makedirs(self.upload_dir, exist_ok=True)
331
+ # Determine if the filename is fully-qualified, and if not, find it in the upload dir
332
+ if not os.path.exists(self.in_filename):
333
+ qualified_in_filename = os.path.join(self.input_dir, self.in_filename)
334
+ if os.path.exists(qualified_in_filename):
335
+ self.in_filename = qualified_in_filename
336
+ else:
337
+ FileConverterInputException(f"Input file {self.in_filename} not found, either absolute or relative "
338
+ f"to {self.input_dir}")
334
339
 
335
340
  # Create directory 'downloads' if not extant.
336
- if not os.path.exists(self.download_dir):
337
- os.makedirs(self.download_dir, exist_ok=True)
341
+ if not os.path.exists(self.output_dir):
342
+ os.makedirs(self.output_dir, exist_ok=True)
338
343
 
339
344
  self.local_filename = os.path.split(self.in_filename)[1]
340
345
  self.filename_base = os.path.splitext(self.local_filename)[0]
341
- self.out_filename = f"{self.download_dir}/{self.filename_base}.{self.to_format_info.name}"
346
+ self.out_filename = f"{self.output_dir}/{self.filename_base}.{self.to_format_info.name}"
342
347
 
343
348
  # Set up files to log to
344
349
  self._setup_loggers()
@@ -441,7 +446,7 @@ class FileConverter:
441
446
  if self.log_mode == const.LOG_FULL_FORCE:
442
447
  self.output_log = self.log_file
443
448
  else:
444
- self.output_log = os.path.join(self.download_dir, f"{self.filename_base}{const.OUTPUT_LOG_EXT}")
449
+ self.output_log = os.path.join(self.output_dir, f"{self.filename_base}{const.OUTPUT_LOG_EXT}")
445
450
 
446
451
  # If any previous log exists, delete it
447
452
  if os.path.exists(self.output_log):