psdi-data-conversion 0.1.6__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.
- psdi_data_conversion-0.2.0/CHANGELOG.md +70 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/CONTRIBUTING.md +76 -14
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/PKG-INFO +9 -2
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/README.md +3 -1
- psdi_data_conversion-0.2.0/psdi_data_conversion/app.py +77 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/constants.py +11 -7
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converter.py +41 -28
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/base.py +18 -13
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/database.py +284 -88
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/__init__.py +5 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/accessibility.py +51 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/env.py +239 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/get.py +53 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/post.py +176 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/gui/setup.py +102 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/main.py +70 -13
- psdi_data_conversion-0.2.0/psdi_data_conversion/static/content/convert.htm +172 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/convertato.htm +36 -26
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/convertc2x.htm +39 -26
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/download.htm +5 -5
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/feedback.htm +2 -2
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/header-links.html +3 -3
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/header-links.html +3 -3
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/psdi-common-header.html +1 -1
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/psdi-common-header.html +1 -1
- psdi_data_conversion-0.2.0/psdi_data_conversion/static/javascript/accessibility.js +223 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/data.js +1 -3
- psdi_data_conversion-0.2.0/psdi_data_conversion/static/javascript/load_accessibility.js +106 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/styles/format.css +74 -20
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/styles/psdi-common.css +5 -0
- psdi_data_conversion-0.2.0/psdi_data_conversion/templates/accessibility.htm +274 -0
- {psdi_data_conversion-0.1.6/psdi_data_conversion/static/content → psdi_data_conversion-0.2.0/psdi_data_conversion/templates}/documentation.htm +25 -5
- psdi_data_conversion-0.2.0/psdi_data_conversion/templates/index.htm +151 -0
- {psdi_data_conversion-0.1.6/psdi_data_conversion/static/content → psdi_data_conversion-0.2.0/psdi_data_conversion/templates}/report.htm +28 -10
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/conversion_test_specs.py +26 -6
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/utils.py +6 -6
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/pyproject.toml +12 -4
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/gui/gui_test.py +8 -3
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/cli_test.py +48 -9
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/database_test.py +35 -4
- psdi_data_conversion-0.1.6/CHANGELOG.md +0 -20
- psdi_data_conversion-0.1.6/psdi_data_conversion/app.py +0 -470
- psdi_data_conversion-0.1.6/psdi_data_conversion/static/content/accessibility.htm +0 -255
- psdi_data_conversion-0.1.6/psdi_data_conversion/static/content/convert.htm +0 -141
- psdi_data_conversion-0.1.6/psdi_data_conversion/static/javascript/accessibility.js +0 -196
- psdi_data_conversion-0.1.6/psdi_data_conversion/static/javascript/load_accessibility.js +0 -89
- psdi_data_conversion-0.1.6/psdi_data_conversion/templates/index.htm +0 -134
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/.gitignore +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/LICENSE +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/__init__.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/LICENSE_ATOMSK +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/LICENSE_C2X +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/linux/atomsk +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/linux/c2x +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/mac/atomsk +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/bin/mac/c2x +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/__init__.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/atomsk.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/c2x.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/openbabel.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/dist.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/file_io.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/log_utility.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/scripts/atomsk.sh +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/scripts/c2x.sh +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/security.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/index-versions/psdi-common-footer.html +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/content/psdi-common-footer.html +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/data/data.json +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/colormode-toggle-dm.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/colormode-toggle-lm.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-icon-dark.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-icon-light.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-darktext-simple.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-darktext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-lighttext-simple.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/psdi-logo-lighttext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-bluesky-black.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-bluesky-white.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-instagram-black.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-instagram-white.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-linkedin-black.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-linkedin-white.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-mastodon-black.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-mastodon-white.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-x-black.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-x-white.svg +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-youtube-black.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/social-logo-youtube-white.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-epsr-logo-darktext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-epsr-logo-lighttext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-logo-darktext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/img/ukri-logo-lighttext.png +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/common.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convert.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convert_common.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convertato.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/convertc2x.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/format.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/psdi-common.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/static/javascript/report.js +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/__init__.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/constants.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/conversion_callbacks.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/testing/gui.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/utils.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/scripts/setup_bin.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/1ARJ.mmcif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/1NE6.mmcif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/5a9z-assembly1.cif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/Fapatite.ins +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/aceticacid.mol +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/benzyne.molden +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.tar +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.tar.gz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/caffeine-smi.zip +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/caffeine.inchi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/ch3cl-esp.cub +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/cyclopropane_err.mol +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/ethanol.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/fullRhinovirus.pdb +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/hemoglobin.pdb +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/nacl.cif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/nacl.mol +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/aceticacid.log.txt +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/aceticacid.mol2 +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine-2D-fastest.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine-3D-best.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_f4_l5_out.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_f4_out.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_kx_out.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/caffeine_a_in_x_out.smi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/hemoglobin_Atomsk.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/hemoglobin_c2x.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/nacl.log +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/nacl.mol +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/quartz_OB.cif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/quartz_OB.log.txt +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/quartz_atomsk.cif +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/quartz_atomsk.log.txt +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/standard_test.inchi +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/xyz_files-mol.zip +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/output/xyz_files.log.txt +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/periodic_dmol3.outmol +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/quartz.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/quartz_err.xyz +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/test_data/standard_test.cdxml +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/converter_test.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/dist_test.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/file_io_test.py +0 -0
- {psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/tests/python/logging_test.py +0 -0
- {psdi_data_conversion-0.1.6 → 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
|
@@ -15,13 +15,13 @@ This project uses a version of [GitLab Flow](https://about.gitlab.com/topics/ver
|
|
15
15
|
|
16
16
|
The following tasks should be completed before merging a release candidate branch to `release`:
|
17
17
|
|
18
|
-
-
|
18
|
+
- Determine the target version based on the changes made:
|
19
19
|
|
20
20
|
- If any breaking changes have been made (after version 1.0.0), the version will advance to the next major version - `X.Y.Z` to `(X+1).0.0`
|
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`)
|
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
|
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.
|
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
|
|
@@ -193,13 +196,13 @@ class MyFileConverter(FileConverter):
|
|
193
196
|
converter = MyFileConverter
|
194
197
|
```
|
195
198
|
|
196
|
-
That's all you need to do! The `psdi_data_conversion.converter` module parses all modules in the `converters` package to find converters, so if you've done everything correctly, it will find the new converter and register it for you. You can test that it is properly registered by using the
|
199
|
+
That's all you need to do! The `psdi_data_conversion.converter` module parses all modules in the `converters` package to find converters, so if you've done everything correctly, it will find the new converter and register it for you. You can test that it is properly registered by using the CLI to run:
|
197
200
|
|
198
201
|
```bash
|
199
202
|
psdi-data-convert -l
|
200
203
|
```
|
201
204
|
|
202
|
-
Your new converter should appear, or else you will probably see an error message which will detail an exception raised when trying to register it. Note that until the converter's information is added to the database (the file `psdi_data_conversion/static/data/data.json`), the
|
205
|
+
Your new converter should appear, or else you will probably see an error message which will detail an exception raised when trying to register it. Note that until the converter's information is added to the database (the file `psdi_data_conversion/static/data/data.json`), the CLI will show that it is unable to perform any conversions, and it will fail on any conversion (believing it to be impossible) unless you provide the `--nc/--no-check` command-line flag.
|
203
206
|
|
204
207
|
For file converters which can be run with a call to a script, this can be streamlined even further by taking advantage of the `ScriptFileConverter` subclass. With this, the converter's subclass can be defined even more succinctly:
|
205
208
|
|
@@ -273,7 +276,7 @@ pip install --editable .[test]
|
|
273
276
|
pytest
|
274
277
|
```
|
275
278
|
|
276
|
-
This installs the project in a virtual environment in "editable" mode (which means the source files will be used from where they are rather than being copied, so any changes to them will be directly reflected in tests and uses of the
|
279
|
+
This installs the project in a virtual environment in "editable" mode (which means the source files will be used from where they are rather than being copied, so any changes to them will be directly reflected in tests and uses of the CLI) and then calls `pytest` to run the unit tests in the project. `pytest` will automatically pick up any extra tests you add and run them as well.
|
277
280
|
|
278
281
|
#### Web App Integration
|
279
282
|
|
@@ -320,13 +323,13 @@ This project uses various GitHub workflows to perform Continuous Integration tas
|
|
320
323
|
- Testing and scanning (triggered by pushes to `main`, `release`, `feature*`, and `rc*` branches)
|
321
324
|
- Periodic checks for updates to common assets
|
322
325
|
- Automatic creation of pull requests for `feature*` and `rc*` branches
|
323
|
-
- Automatic tagging, publishing, and deployment of the `release`
|
326
|
+
- Automatic tagging, publishing, and deployment of the `main` and `release` branches to the development, staging and production environments
|
324
327
|
|
325
|
-
See the
|
328
|
+
See the comments within the files for further details. See also the [section on deployment](#deployment) for details specific to deployment tasks.
|
326
329
|
|
327
330
|
## Publishing
|
328
331
|
|
329
|
-
The Python library,
|
332
|
+
The Python library, CLI, and local GUI are published as a Python package via PyPI. This section describes how the package is set up and how it's published.
|
330
333
|
|
331
334
|
### Package Setup
|
332
335
|
|
@@ -338,7 +341,7 @@ The version of the package is set to be determined from the version control syst
|
|
338
341
|
|
339
342
|
### Initial Publication
|
340
343
|
|
341
|
-
This section details the
|
344
|
+
This section details the procedure for the initial publication of this package - now that this is complete, this section is left in for reference in case of future need.
|
342
345
|
|
343
346
|
First, it's necessary to install a couple required packages in order to build a Python package: `build` to build it and `twine` to upload it. These can be installed with pip via:
|
344
347
|
|
@@ -376,8 +379,67 @@ The management page can also be used to add or remove collaborators through the
|
|
376
379
|
|
377
380
|
## Deployment
|
378
381
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
+
The `ci-main.yml`, `ci-release.yml` and `ci-deploy-production.yml` files in the `.github/workflows` directory house workflows which deploy
|
383
|
+
the data conversion service to [Kubernetes](https://kubernetes.io/) clusters hosted in STFC. There are three clusters, each of which correspond
|
384
|
+
to a different deployment _environment_ for the data conversion service. The three environments are `development`, `staging` and `production`.
|
385
|
+
Deployment to `development`, `staging` and `production` is done from either the `main` or `release` branch. The table below indicates which
|
386
|
+
branch deploys to which environment. The table also shows, for each environment:
|
387
|
+
|
388
|
+
- the URL on which the service is exposed once it is successfully deployed
|
389
|
+
- the accessibility of the service. Depending on the environment the service is either accessible to the _public_ at the specified URL,
|
390
|
+
or accessible only to IP addresses within the _STFC and University of Southampton subnets_
|
391
|
+
- the trigger used to invoke the workflow which deploys the service from the source branch. Deployment is either _automatic_
|
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
|
393
|
+
developer.
|
394
|
+
|
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 |
|
400
|
+
|
401
|
+
Thus the `main` is automatically deployed to the `development` environment, and the `release` branch is automatically deployed to the `staging`
|
402
|
+
environment. However deployment from the `release` branch to the `production` environment is a manual process. This is to allow developers to
|
403
|
+
manually check that the `release` version works correctly in the `staging` environment before deploying it to the `production` environment.
|
404
|
+
The checks to `staging` before deployment to `production` should echo those described in the above
|
405
|
+
section [Release Checklist and Procedure](#release-checklist-and-procedure).
|
406
|
+
|
407
|
+
### How to deploy to the `production` environment
|
408
|
+
|
409
|
+
To trigger the workflow which deploys the service to the `production` environment, from the [main page of the repo](https://github.com/PSDI-UK/psdi-data-conversion)
|
410
|
+
navigate to [Actions](https://github.com/PSDI-UK/psdi-data-conversion/actions). Here you should see on the right a list of recent workflow
|
411
|
+
runs, including whether or not they are successful (as indicated by a green tick); and on the left you should see a list of all workflows.
|
412
|
+
|
413
|
+
The workflow which deploys the `release` branch to the `staging` environment is named `CI - Release`. As mentioned above, you should verify
|
414
|
+
that this workflow successfully deployed the `release` version to `staging` before considering deploying to `production`. If you click on the
|
415
|
+
latest workflow run of `CI - Release` then you can see a breakdown of the workflow into its constituent workflows. Note the `deploy-stfc-staging-k8s`
|
416
|
+
job. If this job is successful then the `release` version has been successfully deployed to `staging`.
|
417
|
+
|
418
|
+
Assuming this is the case, navigating back to [Actions](https://github.com/PSDI-UK/psdi-data-conversion/actions), note that there is a workflow
|
419
|
+
listed on the left named `CI - Deploy to production cluster`. This is the workflow which must be invoked manually to deploy the `release`
|
420
|
+
version to the `production` environment. Clicking on the link to this workflow gives
|
421
|
+
[a list of recent invocations](https://github.com/PSDI-UK/psdi-data-conversion/actions/workflows/ci-deploy-production.yml) of the workflow.
|
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
|
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
|
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
|
425
|
+
same page.
|
426
|
+
|
427
|
+
### Further technical details
|
428
|
+
|
429
|
+
The `ci-main.yml`, `ci-release.yml` and `ci-deploy-production.yml` workflows leverage the `job-deploy-k8s.yml` callable workflow to do the heavy
|
430
|
+
lifting with regards to deployment to STFC Kubernetes environments. The `job-deploy-k8s.yml` workflow is coded to be invoked on PSDI's GitHub
|
431
|
+
runners. These runners are hosted within STFC's network, providing a means to access the three STFC Kubernetes clusters corresponding to the
|
432
|
+
`development`, `staging` and `production` environments. The environment to be targeted for deployment is passed to the `job-deploy-k8s.yml`
|
433
|
+
workflow as an input parameter. Given a target environment `<env>`, the `job-deploy-k8s.yml` workflow will deploy the service to the
|
434
|
+
the `<env>` environment using the Kubernetes manifests stored in the `deploy`/<env>` directory of this repository.
|
435
|
+
|
436
|
+
The workflow relies on several repository secrets, namely `KUBECONF`, `IMAGEPULLSECRET`, `CERTIFICATE_PRIVATE_KEY` and `CERTIFICATE_PEM` for
|
437
|
+
various purposes.
|
438
|
+
|
439
|
+
- `KUBECONF` provides Kubernetes-specific information pertaining to the the Kubernetes cluster for the target environment. Note that
|
440
|
+
`KUBECONF` is an _environment_-dependent secret, taking different values for each of the environments.
|
441
|
+
- `IMAGEPULLSECRET` enables the container image housing the data conversion service to be pulled from this GitHub repo to the PSDI runner
|
442
|
+
- `CERTIFICATE_PRIVATE_KEY` and `CERTIFICATE_PEM` pertain to the TLS certificates for the service
|
443
|
+
For further information see the `job-deploy-k8s.yml` file and aforementioned Kubernetes manifests.
|
382
444
|
|
383
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.
|
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
|
@@ -243,6 +248,9 @@ Description-Content-Type: text/markdown
|
|
243
248
|
|
244
249
|
# PSDI Data Conversion
|
245
250
|
|
251
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
252
|
+

|
253
|
+
|
246
254
|
Release date: 2024-04-29
|
247
255
|
|
248
256
|
This is the repository for the PSDI PF2 Chemistry File Format Conversion project. The goal of this project is to provide utilities to assist in converting files between the many different file formats used in chemistry, providing information on what converters are available for a given conversion and the expected quality of it, and providing multiple interfaces to perform these conversions. These interfaces are:
|
@@ -327,7 +335,6 @@ This is the repository for the PSDI PF2 Chemistry File Format Conversion project
|
|
327
335
|
- `LICENSE` (Apache License version 2.0)
|
328
336
|
- `pyproject.toml` (Python project metadata and settings)
|
329
337
|
- `README.md` (This file)
|
330
|
-
- `requirements.txt` (Requirements for the web app deployment of this project)
|
331
338
|
|
332
339
|
## Requirements
|
333
340
|
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# PSDI Data Conversion
|
2
2
|
|
3
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
4
|
+

|
5
|
+
|
3
6
|
Release date: 2024-04-29
|
4
7
|
|
5
8
|
This is the repository for the PSDI PF2 Chemistry File Format Conversion project. The goal of this project is to provide utilities to assist in converting files between the many different file formats used in chemistry, providing information on what converters are available for a given conversion and the expected quality of it, and providing multiple interfaces to perform these conversions. These interfaces are:
|
@@ -84,7 +87,6 @@ This is the repository for the PSDI PF2 Chemistry File Format Conversion project
|
|
84
87
|
- `LICENSE` (Apache License version 2.0)
|
85
88
|
- `pyproject.toml` (Python project metadata and settings)
|
86
89
|
- `README.md` (This file)
|
87
|
-
- `requirements.txt` (Requirements for the web app deployment of this project)
|
88
90
|
|
89
91
|
## Requirements
|
90
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
|
-
|
56
|
-
|
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
|
-
|
185
|
+
input_dir : str
|
188
186
|
The location of input files relative to the current directory
|
189
|
-
|
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
|
-
|
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
|
-
|
359
|
+
input_dir : str
|
355
360
|
The location of input files relative to the current directory
|
356
|
-
|
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(
|
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(
|
438
|
+
l_run_output.append(_run_single_file_conversion(filename,
|
429
439
|
to_format,
|
430
440
|
*args,
|
431
441
|
from_format=from_format,
|
432
|
-
|
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)
|
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(
|
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 =
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
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 [
|
579
|
-
|
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
|
-
|
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'
|
{psdi_data_conversion-0.1.6 → psdi_data_conversion-0.2.0}/psdi_data_conversion/converters/base.py
RENAMED
@@ -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
|
-
|
210
|
-
|
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
|
-
|
238
|
+
input_dir : str
|
239
239
|
The location of input files relative to the current directory
|
240
|
-
|
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.
|
300
|
-
self.
|
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
|
-
#
|
332
|
-
if not os.path.exists(self.
|
333
|
-
os.
|
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.
|
337
|
-
os.makedirs(self.
|
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.
|
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.
|
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):
|