psdi-data-conversion 0.0.37__py3-none-any.whl → 0.0.39__py3-none-any.whl

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 (30) hide show
  1. psdi_data_conversion/app.py +64 -14
  2. psdi_data_conversion/constants.py +6 -5
  3. psdi_data_conversion/converter.py +20 -13
  4. psdi_data_conversion/converters/base.py +75 -68
  5. psdi_data_conversion/converters/c2x.py +14 -0
  6. psdi_data_conversion/converters/openbabel.py +12 -11
  7. psdi_data_conversion/database.py +361 -115
  8. psdi_data_conversion/dist.py +2 -1
  9. psdi_data_conversion/file_io.py +1 -2
  10. psdi_data_conversion/log_utility.py +1 -1
  11. psdi_data_conversion/main.py +152 -70
  12. psdi_data_conversion/static/content/index-versions/psdi-common-footer.html +12 -8
  13. psdi_data_conversion/static/content/psdi-common-footer.html +12 -8
  14. psdi_data_conversion/static/data/data.json +617 -3
  15. psdi_data_conversion/static/javascript/convert.js +54 -6
  16. psdi_data_conversion/static/javascript/convert_common.js +16 -2
  17. psdi_data_conversion/static/javascript/data.js +36 -4
  18. psdi_data_conversion/static/javascript/format.js +22 -9
  19. psdi_data_conversion/static/styles/format.css +7 -0
  20. psdi_data_conversion/templates/index.htm +57 -48
  21. psdi_data_conversion/testing/constants.py +3 -0
  22. psdi_data_conversion/testing/conversion_callbacks.py +4 -3
  23. psdi_data_conversion/testing/conversion_test_specs.py +44 -20
  24. psdi_data_conversion/testing/gui.py +362 -294
  25. psdi_data_conversion/testing/utils.py +38 -19
  26. {psdi_data_conversion-0.0.37.dist-info → psdi_data_conversion-0.0.39.dist-info}/METADATA +88 -4
  27. {psdi_data_conversion-0.0.37.dist-info → psdi_data_conversion-0.0.39.dist-info}/RECORD +30 -30
  28. {psdi_data_conversion-0.0.37.dist-info → psdi_data_conversion-0.0.39.dist-info}/WHEEL +0 -0
  29. {psdi_data_conversion-0.0.37.dist-info → psdi_data_conversion-0.0.39.dist-info}/entry_points.txt +0 -0
  30. {psdi_data_conversion-0.0.37.dist-info → psdi_data_conversion-0.0.39.dist-info}/licenses/LICENSE +0 -0
@@ -7,7 +7,9 @@
7
7
 
8
8
 
9
9
  import { getInputFlags, getOutputFlags, getInputArgFlags, getOutputArgFlags } from "./data.js";
10
- import { commonConvertReady, convertFile, getExtCheck, splitArchiveExt, isArchiveExt } from "./convert_common.js"
10
+ import {
11
+ SAFE_CHAR_REGEX, commonConvertReady, convertFile, getExtCheck, splitArchiveExt, isArchiveExt
12
+ } from "./convert_common.js"
11
13
 
12
14
  var token = "",
13
15
  in_ext = "",
@@ -51,8 +53,24 @@ function enterArgument(event) {
51
53
  }
52
54
  }
53
55
 
56
+
57
+ /**
58
+ * Validate the input for a format option - if invalid, display the error message, if valid, hide it
59
+ *
60
+ * @param {*} event
61
+ */
62
+ function validateInput(event) {
63
+ var err_id = this.id.replace('text', 'err')
64
+ if (this.validity.patternMismatch) {
65
+ $('#' + err_id).css({ display: "block" })
66
+ } else {
67
+ $('#' + err_id).css({ display: "none" })
68
+ }
69
+ }
70
+
54
71
  // Uploads a user-supplied file
55
72
  function submitFile() {
73
+
56
74
  const file = $("#fileToUpload")[0].files[0],
57
75
  [fname, ext] = splitArchiveExt(file.name);
58
76
 
@@ -78,9 +96,16 @@ function submitFile() {
78
96
  const checked_in = $('input[name=in_arg_check]:checked'),
79
97
  checked_out = $('input[name=out_arg_check]:checked');
80
98
 
99
+ let security_passed = true;
100
+
81
101
  checked_in.each(function () {
82
102
  read_arg_flags += $("#" + this.id).val()[0];
83
- const arg = $("#in_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
103
+ const e = $("#in_arg_text" + this.id.substring(this.id.length - 1, this.id.length));
104
+ const arg = e.val();
105
+
106
+ if (e[0].validity.patternMismatch) {
107
+ security_passed = false;
108
+ }
84
109
 
85
110
  if (/\S/.test(arg)) {
86
111
  read_args += arg.trim() + '£';
@@ -92,7 +117,12 @@ function submitFile() {
92
117
 
93
118
  checked_out.each(function () {
94
119
  write_arg_flags += $("#" + this.id).val()[0];
95
- const arg = $("#out_arg_text" + this.id.substring(this.id.length - 1, this.id.length)).val();
120
+ const e = $("#out_arg_text" + this.id.substring(this.id.length - 1, this.id.length));
121
+ const arg = e.val();
122
+
123
+ if (e[0].validity.patternMismatch) {
124
+ security_passed = false;
125
+ }
96
126
 
97
127
  if (/\S/.test(arg)) {
98
128
  write_args += arg.trim() + '£';
@@ -102,9 +132,21 @@ function submitFile() {
102
132
  }
103
133
  })
104
134
 
135
+ let alert_msg = '';
136
+
137
+ if (!security_passed) {
138
+ alert_msg += 'ERROR: One or more ticked options contains invalid characters. They must match the regex /' +
139
+ SAFE_CHAR_REGEX + '/ .\n';
140
+ }
141
+
105
142
  if (!all_args_entered) {
106
- alert('All ticked option flags need additional information to be entered into the associated text box.');
107
- return;
143
+ alert_msg += 'ERROR: All ticked options need additional information to be entered into the associated ' +
144
+ 'text box.\n';
145
+ }
146
+
147
+ if (alert_msg) {
148
+ alert(alert_msg);
149
+ return
108
150
  }
109
151
 
110
152
  const coordinates = $('input[name="coordinates"]:checked').val(),
@@ -216,11 +258,17 @@ function addCheckboxes(argFlags, type) {
216
258
  <tr>
217
259
  <td><input type='checkbox' id="${type}_check${flagCount}" name=${type}_check value="${flag}"></input></td>
218
260
  <td><label for="${type}_check${flagCount}">${flag} [${brief}]: ${description}<label></td>
219
- <td><input type='text' id=${type}_text${flagCount} placeholder='-- type info. here --'></input></td>
261
+ <td><input type='text' id="${type}_text${flagCount}" placeholder='-- type info. here --'
262
+ pattern='` + SAFE_CHAR_REGEX + `'></input>
263
+ <p class="init-hidden" id="${type}_err${flagCount}"><strong>ERROR:</strong> Input contains
264
+ invalid characters; it must match the regex
265
+ <code class="secondary">/` + SAFE_CHAR_REGEX + `/</code></p>
266
+ </td>
220
267
  <td><span id= ${type}_label${flagCount}>${furtherInfo}</span></td>
221
268
  </tr>`);
222
269
 
223
270
  $(`#${type}_text${flagCount}`).hide();
271
+ $(`#${type}_text${flagCount}`).on('input', validateInput);
224
272
  $(`#${type}_label${flagCount}`).hide();
225
273
  $(`#${type}_check${flagCount}`).change(enterArgument);
226
274
 
@@ -18,6 +18,20 @@ const TARGZ_EXT = "tar.gz"
18
18
  const TARBZ_EXT = "tar.bz"
19
19
  const TARXZ_EXT = "tar.xz"
20
20
 
21
+ // Short list of safe allowed characters:
22
+ // \w: All letters and digits
23
+ // \s: All whitespace characters
24
+ // .: Period
25
+ // \-: Hyphen
26
+ // :: Colon
27
+ // +: Plus symbol
28
+ // *: Asterisk
29
+ // =: Equals sign
30
+ // $: Dollar sign
31
+ // /: Forward-slash
32
+ // \\: Backslash
33
+ export const SAFE_CHAR_REGEX = "[\\w\\s.\\-:+*=$\\/\\\\]*"
34
+
21
35
  // Whether or not file extensions will be checked
22
36
  let extCheck = true;
23
37
 
@@ -271,10 +285,10 @@ function checkFile(event) {
271
285
  }
272
286
 
273
287
  /**
274
- * Allow the file upload to only accept the expected type of file
288
+ * Allow the file upload to only accept the expected type of file, plus archives
275
289
  */
276
290
  function limitFileType() {
277
- $("#fileToUpload")[0].accept = "." + in_ext;
291
+ $("#fileToUpload")[0].accept = "." + in_ext + ", .zip, .tar, .tar.gz, .tar.xz, .tar.bz";
278
292
  }
279
293
 
280
294
  /**
@@ -1,7 +1,21 @@
1
1
  // data.js
2
2
 
3
3
  const response = await fetch("/static/data/data.json");
4
- const data = JSON.parse(await response.text());
4
+
5
+ let data = null;
6
+ try {
7
+ data = JSON.parse(await response.text());
8
+ } catch (err) {
9
+ console.log("ERROR: Database could not be loaded, error: " + err)
10
+ }
11
+
12
+ /**
13
+ * Indicates whether or not the database was successfully loaded
14
+ * @returns {boolean}
15
+ */
16
+ export function databaseLoaded() {
17
+ return data !== null;
18
+ }
5
19
 
6
20
  const collator = new Intl.Collator();
7
21
 
@@ -49,6 +63,24 @@ export async function getOutputFormats() {
49
63
  return outFormats.sort((a, b) => compare([a.extension, b.extension], [a.note, b.note]))
50
64
  }
51
65
 
66
+ /**
67
+ * Gets the ID for a format, given its extension and note
68
+ *
69
+ * @param {string} extension - The extension of the format, e.g. 'pdb'
70
+ * @param {string} note - The note of the format, e.g. 'Protein Databank'
71
+ * @returns {(int|null)} - The ID of the format if found, or else null
72
+ */
73
+ export async function getFormatId(extension, note) {
74
+
75
+ var format = (data.formats.filter(format => (format.extension === extension) && (format.note === note)));
76
+
77
+ if (format === undefined) {
78
+ return null;
79
+ }
80
+
81
+ return format[0].id;
82
+ }
83
+
52
84
  export async function getOutputFormatsForInputFormat(inExtension, inNote) {
53
85
 
54
86
  const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0];
@@ -84,7 +116,7 @@ export async function getConverters(inExtension, inNote, outExtension, outNote)
84
116
  const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0];
85
117
  const outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
86
118
 
87
- if ((inputFormat === undefined) || (outputFormat === undefined)) {
119
+ if ((inputFormat === undefined) || (outputFormat === undefined)) {
88
120
  return [];
89
121
  }
90
122
 
@@ -96,7 +128,7 @@ export async function getConverters(inExtension, inNote, outExtension, outNote)
96
128
  name: convertersById.get(conversion.converters_id).name
97
129
  }));
98
130
 
99
- return convertersWithDegreeOfSuccess.sort((a, b) => compare(a.name, b.name ));
131
+ return convertersWithDegreeOfSuccess.sort((a, b) => compare(a.name, b.name));
100
132
  }
101
133
 
102
134
  export async function getConverterByName(name) {
@@ -170,7 +202,7 @@ export async function getOutputArgFlags(extension, note) {
170
202
  export async function getLevelChemInfo(inExtension, inNote, outExtension, outNote) {
171
203
 
172
204
  const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0],
173
- outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
205
+ outputFormat = (data.formats.filter(format => (format.extension === outExtension) && (format.note === outNote)))[0];
174
206
 
175
207
  return [inputFormat, outputFormat];
176
208
  }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { disableDirtyForms, cleanDirtyForms, initDirtyForms, loadServiceMode, loadProductionMode } from "./common.js";
9
9
  import {
10
- getInputFormats, getOutputFormats, getOutputFormatsForInputFormat,
10
+ databaseLoaded, getInputFormats, getOutputFormats, getOutputFormatsForInputFormat,
11
11
  getInputFormatsForOutputFormat, getConverters, getConverterByName, getLevelChemInfo
12
12
  } from "./data.js";
13
13
 
@@ -18,15 +18,20 @@ var fromList = new Array(),
18
18
 
19
19
  $(document).ready(function () {
20
20
 
21
- // Populates the "Convert from" selection list
22
- getInputFormats().then((formats) => {
23
- populateList(formats, "from");
24
- });
21
+ // Populate the available formats if the database successfully loaded, otherwise display an error message
22
+ if (databaseLoaded()) {
23
+ // Populates the "Convert from" selection list
24
+ getInputFormats().then((formats) => {
25
+ populateList(formats, "from");
26
+ });
25
27
 
26
- // Populates the "Convert to" selection list
27
- getOutputFormats().then((formats) => {
28
- populateList(formats, "to");
29
- });
28
+ // Populates the "Convert to" selection list
29
+ getOutputFormats().then((formats) => {
30
+ populateList(formats, "to");
31
+ });
32
+ } else {
33
+ displayDatabaseLoadError();;
34
+ }
30
35
 
31
36
  sessionStorage.setItem("token", token);
32
37
  sessionStorage.setItem("max_file_size", max_file_size);
@@ -52,6 +57,14 @@ $(document).ready(function () {
52
57
  initDirtyForms();
53
58
  });
54
59
 
60
+ /**
61
+ * Hides the format and converter selection and displays an error message that the database could not be loaded.
62
+ */
63
+ function displayDatabaseLoadError() {
64
+ $("#format-selection").css({ display: "none" });
65
+ $("#database-error").css({ display: "block" });
66
+ }
67
+
55
68
  /**
56
69
  * Gets the input and output extensions and their notes from what's currently selected in the search boxes.
57
70
  * @returns {Array<str>} Input extension, Input note, Output extension, Output note
@@ -44,6 +44,13 @@ form {
44
44
  }
45
45
  }
46
46
 
47
+ /* Invalid input fields switch to alternate background */
48
+
49
+ input:invalid {
50
+ background-color: var(--ifm-color-primary);
51
+ color : var(--ifm-hero-text-color);
52
+ }
53
+
47
54
  /* Converter details, user input and file conversion initially not displayed. */
48
55
  .init-hidden {
49
56
  display: none
@@ -60,55 +60,64 @@
60
60
  <p>Your one-stop shop for file format conversion, PSDI's Data Conversion Service enables users to seamlessly
61
61
  convert between different file formats and assess the quality of proposed conversions. This is the web version
62
62
  of our service. To find out more about Data Conversion and our other tools, click
63
- <a href="https://resources.psdi.ac.uk/resource-themes/7bcc430a-fdc9-413e-bf32-bf163236430b"
64
- id="more" target="_blank">here.</a></p>
65
- <p>Select 'from' and 'to' file formats in the 'Convert from/to' boxes, in either order. Typing where indicated
66
- filters the options (case insensitive); for example, typing 'can' or 'NON' reduces the number of options to one:
67
- 'can: Canonical SMILES.' If you change your mind about a conversion, it is advisable to click on the 'Reset'
68
- button. When both formats have been selected, converters able to carry out this conversion appear in the
69
- 'Conversion options' box along with an indication of conversion quality (many conversions have not yet been
70
- tested) and whether or not the converter is supported on this site.</p>
71
- <p>
72
- <label for="searchFrom" id="fromLabel">Convert from:</label><br>
73
- <input type="text" placeholder="-- type here to filter options --" size="12" id="searchFrom"
74
- class="large-width"><br>
75
- <select size="4" id="fromList" class="large-width"></select>
63
+ <a href="https://resources.psdi.ac.uk/resource-themes/7bcc430a-fdc9-413e-bf32-bf163236430b" id="more"
64
+ target="_blank">here.</a>
76
65
  </p>
77
- <div class="smallGap"></div>
78
- <p>
79
- <label for="searchTo" id="toLabel">Convert to:</label><br>
80
- <input type="text" placeholder="-- type here to filter options --" size="12" id="searchTo"
81
- class="large-width"><br>
82
- <select size="4" id="toList" class="large-width"></select>
83
- </p>
84
- <input type="button" class="button" value=" Reset " name="resetButton" id="resetButton">
85
- <br><br>
86
- <p>Selecting a converter displays information
87
- about it, along with a link to a relevant website. Selecting a supported converter affords the opportunity to
88
- carry out a conversion on this site. Clicking on the 'Yes' button takes us to the 'Conversion' page. If a
89
- file format has not been found, or if there are no converters capable of carrying out a required conversion
90
- please click on 'Report Missing Format/Conversion' in the navigation bar.</p>
91
- <p>
92
- <label for="success">Select from available conversion
93
- options:</label><br>
94
- <select size="4" id="success" class="large-width"></select>
95
- </p>
96
- <span class="normalText">Show how the conversion quality was determined for the selected converter.</span>
97
- <input type="button" class="button" value=" Show " name="showButton" id="showButton">
98
- <br>
99
- <h6>Converter details:</h6>
100
- <p id="converter" , class="init-hidden">
101
- <span id="name"></span>
102
- <br><span id="description"></span>
103
- <br><span id="url"></span>
104
- <br><span id="info"></span>
105
- <a id="visit" target="_blank">this website.</a>
106
- <div id="formatWarning" class="init-hidden"></div>
107
- <div id="offer" class="init-hidden">
108
- <span id="question"></span>
109
- <input type="button" class="button" value=" Yes " name="yesButton" id="yesButton">
66
+ <div id="format-selection">
67
+ <p>Select 'from' and 'to' file formats in the 'Convert from/to' boxes, in either order. Typing where indicated
68
+ filters the options (case insensitive); for example, typing 'can' or 'NON' reduces the number of options to
69
+ one:
70
+ 'can: Canonical SMILES.' If you change your mind about a conversion, it is advisable to click on the 'Reset'
71
+ button. When both formats have been selected, converters able to carry out this conversion appear in the
72
+ 'Conversion options' box along with an indication of conversion quality (many conversions have not yet been
73
+ tested) and whether or not the converter is supported on this site.</p>
74
+ <p>
75
+ <label for="searchFrom" id="fromLabel">Convert from:</label><br>
76
+ <input type="text" placeholder="-- type here to filter options --" size="12" id="searchFrom"
77
+ class="large-width"><br>
78
+ <select size="4" id="fromList" class="large-width"></select>
79
+ </p>
80
+ <div class="smallGap"></div>
81
+ <p>
82
+ <label for="searchTo" id="toLabel">Convert to:</label><br>
83
+ <input type="text" placeholder="-- type here to filter options --" size="12" id="searchTo"
84
+ class="large-width"><br>
85
+ <select size="4" id="toList" class="large-width"></select>
86
+ </p>
87
+ <input type="button" class="button" value=" Reset " name="resetButton" id="resetButton">
88
+ <br><br>
89
+ <p>Selecting a converter displays information
90
+ about it, along with a link to a relevant website. Selecting a supported converter affords the opportunity to
91
+ carry out a conversion on this site. Clicking on the 'Yes' button takes us to the 'Conversion' page. If a
92
+ file format has not been found, or if there are no converters capable of carrying out a required conversion
93
+ please click on 'Report Missing Format/Conversion' in the navigation bar.</p>
94
+ <p>
95
+ <label for="success">Select from available conversion
96
+ options:</label><br>
97
+ <select size="4" id="success" class="large-width"></select>
98
+ </p>
99
+ <span class="normalText">Show how the conversion quality was determined for the selected converter.</span>
100
+ <input type="button" class="button" value=" Show " name="showButton" id="showButton">
101
+ <br>
102
+ <h6>Converter details:</h6>
103
+ <p id="converter" , class="init-hidden">
104
+ <span id="name"></span>
105
+ <br><span id="description"></span>
106
+ <br><span id="url"></span>
107
+ <br><span id="info"></span>
108
+ <a id="visit" target="_blank">this website.</a>
109
+ <div id="formatWarning" class="init-hidden"></div>
110
+ <div id="offer" class="init-hidden">
111
+ <span id="question"></span>
112
+ <input type="button" class="button" value=" Yes " name="yesButton" id="yesButton">
113
+ </div>
114
+ </p>
115
+ </div>
116
+ <div id="database-error" class="init-hidden">
117
+ <p><strong>ERROR:</strong> Connection to the conversion database failed. Please try refreshing this page. If
118
+ this issue persists, please report it to us using the "Contact" link in the header. You can also download
119
+ a version of this service for local use using the "Download" link in the header if you'd prefer.</p>
110
120
  </div>
111
- </p>
112
121
  <div class="medGap"></div>
113
122
  </div>
114
123
  </form>
@@ -123,4 +132,4 @@
123
132
 
124
133
  </body>
125
134
 
126
- </html>
135
+ </html>
@@ -13,3 +13,6 @@ TEST_DATA_LOC_IN_PROJECT = "./test_data"
13
13
 
14
14
  INPUT_TEST_DATA_LOC_IN_PROJECT = TEST_DATA_LOC_IN_PROJECT
15
15
  OUTPUT_TEST_DATA_LOC_IN_PROJECT = os.path.join(TEST_DATA_LOC_IN_PROJECT, "output")
16
+
17
+ DEFAULT_ORIGIN = "http://127.0.0.1:5000"
18
+ """The default location of the server for running GUI unit tests"""
@@ -6,10 +6,10 @@ conversion test, run with the functions and classes defined in the `utils.py` mo
6
6
  """
7
7
 
8
8
  import abc
9
- from collections.abc import Callable, Iterable
10
- from dataclasses import dataclass, field
11
9
  import os
12
10
  import re
11
+ from collections.abc import Callable, Iterable
12
+ from dataclasses import dataclass, field
13
13
  from tempfile import TemporaryDirectory
14
14
 
15
15
  from psdi_data_conversion.constants import DATETIME_RE_RAW
@@ -352,7 +352,8 @@ class CheckException:
352
352
 
353
353
  # Check the exception type
354
354
  if self.ex_type and not issubclass(exc_info.type, self.ex_type):
355
- l_errors.append(f"ERROR: Raised exception is of type '{exc_info.type}', but expected '{self.ex_type}'")
355
+ l_errors.append(f"ERROR: Raised exception is of type '{exc_info.type}', but expected '{self.ex_type}'. "
356
+ f"Raised exception's message was: {str(exc_info)}")
356
357
 
357
358
  exc = exc_info.value
358
359
 
@@ -8,17 +8,18 @@ application, and GUI.
8
8
 
9
9
  from psdi_data_conversion import constants as const
10
10
  from psdi_data_conversion.converters.atomsk import CONVERTER_ATO
11
- from psdi_data_conversion.converters.base import (FileConverterAbortException, FileConverterHelpException,
12
- FileConverterInputException, FileConverterSizeException)
11
+ from psdi_data_conversion.converters.base import (FileConverterAbortException, FileConverterInputException,
12
+ FileConverterSizeException)
13
13
  from psdi_data_conversion.converters.c2x import CONVERTER_C2X
14
14
  from psdi_data_conversion.converters.openbabel import CONVERTER_OB, COORD_GEN_KEY, COORD_GEN_QUAL_KEY
15
- from psdi_data_conversion.testing.conversion_callbacks import (CheckArchiveContents, CheckException, CheckLogContents,
16
- CheckLogContentsSuccess, CheckFileStatus,
15
+ from psdi_data_conversion.database import FileConverterDatabaseException
16
+ from psdi_data_conversion.testing.conversion_callbacks import (CheckArchiveContents, CheckException, CheckFileStatus,
17
+ CheckLogContents, CheckLogContentsSuccess,
17
18
  CheckStderrContents, CheckStdoutContents,
18
- MatchOutputFile, MultiCallback as MCB)
19
+ MatchOutputFile)
20
+ from psdi_data_conversion.testing.conversion_callbacks import MultiCallback as MCB
19
21
  from psdi_data_conversion.testing.utils import ConversionTestSpec as Spec
20
22
 
21
-
22
23
  l_all_test_specs: list[Spec] = []
23
24
  """All test specs defined in this file"""
24
25
 
@@ -36,11 +37,16 @@ l_all_test_specs.append(Spec(name="Standard Multiple Tests",
36
37
  "hemoglobin.pdb", "hemoglobin.pdb", "nacl.cif",
37
38
  "hemoglobin.pdb", "hemoglobin.pdb", "nacl.cif",
38
39
  "ethanol.xyz"],
39
- to_format=["pdb",
40
+ to_format=["pdb-0",
40
41
  "cif", "mol2", "xyz",
41
42
  "cif", "xyz", "xyz",
42
- "cif", "xyz", "xyz",
43
+ "cif", "xyz-0", "xyz-0",
43
44
  "cml"],
45
+ from_format=[None,
46
+ None, None, None,
47
+ None, None, None,
48
+ "pdb-0", "pdb-0", None,
49
+ None],
44
50
  converter_name=[CONVERTER_OB,
45
51
  CONVERTER_OB, CONVERTER_OB, CONVERTER_OB,
46
52
  CONVERTER_ATO, CONVERTER_ATO, CONVERTER_ATO,
@@ -52,6 +58,17 @@ l_all_test_specs.append(Spec(name="Standard Multiple Tests",
52
58
  """A basic set of test conversions which we expect to succeed without issue, running conversions with each of the
53
59
  Open Babel, Atomsk, and c2x converters"""
54
60
 
61
+ l_all_test_specs.append(Spec(name="c2x Formats Tests",
62
+ to_format=["res", "abi", "POSCAR", "cml"],
63
+ converter_name=CONVERTER_C2X,
64
+ callback=MCB(CheckFileStatus(),
65
+ CheckLogContentsSuccess()),
66
+ compatible_with_gui=False,
67
+ ))
68
+ """Test converting with c2x to a few different formats which require special input. This test isn't run in the GUI
69
+ solely to save on resources, since there are unlikely to be an GUI-specific issues raised by this test that aren't
70
+ caught in others."""
71
+
55
72
  archive_callback = MCB(CheckFileStatus(),
56
73
  CheckArchiveContents(l_filename_bases=["caffeine-no-flags",
57
74
  "caffeine-ia",
@@ -65,7 +82,7 @@ l_all_test_specs.append(Spec(name="Archive",
65
82
  filename=["caffeine-smi.zip",
66
83
  "caffeine-smi.tar",
67
84
  "caffeine-smi.tar.gz"],
68
- conversion_kwargs={"from_format": "smi"},
85
+ from_format="smi",
69
86
  to_format="inchi",
70
87
  callback=archive_callback,
71
88
  ))
@@ -74,8 +91,8 @@ l_all_test_specs.append(Spec(name="Archive",
74
91
  l_all_test_specs.append(Spec(name="Archive (wrong format) - Library and CLA",
75
92
  filename="caffeine-smi.zip",
76
93
  to_format="inchi",
77
- conversion_kwargs=[{"from_format": "pdb"},
78
- {"from_format": "pdb", "strict": True}],
94
+ from_format=["pdb-0", "pdb-0"],
95
+ conversion_kwargs=[{}, {"strict": True}],
79
96
  expect_success=[True, False],
80
97
  callback=[CheckStderrContents(const.ERR_WRONG_EXTENSIONS),
81
98
  CheckException(ex_type=FileConverterInputException,
@@ -88,8 +105,8 @@ l_all_test_specs.append(Spec(name="Archive (wrong format) - Library and CLA",
88
105
  l_all_test_specs.append(Spec(name="Archive (wrong format) - GUI",
89
106
  filename="caffeine-smi.zip",
90
107
  to_format="inchi",
91
- conversion_kwargs=[{"from_format": "pdb"},
92
- {"from_format": "pdb", "strict": True}],
108
+ from_format=["pdb-0", "pdb-0"],
109
+ conversion_kwargs=[{}, {"strict": True}],
93
110
  expect_success=[False, False],
94
111
  callback=CheckException(ex_type=FileConverterInputException,
95
112
  ex_message=const.ERR_WRONG_EXTENSIONS),
@@ -150,7 +167,7 @@ Not compatible with GUI tests, since the GUI doesn't support quiet mode
150
167
 
151
168
  l_all_test_specs.append(Spec(name="Open Babel Warning",
152
169
  filename="1NE6.mmcif",
153
- to_format="pdb",
170
+ to_format="pdb-0",
154
171
  callback=CheckLogContentsSuccess(["Open Babel Warning",
155
172
  "Failed to kekulize aromatic bonds",])
156
173
  ))
@@ -204,7 +221,8 @@ Not compatible with the GUI, since the GUI can't forcibly delete files uploaded
204
221
 
205
222
  l_all_test_specs.append(Spec(name="Failed conversion - bad input file",
206
223
  filename=["quartz_err.xyz", "cyclopropane_err.mol"],
207
- to_format=["inchi", "xyz"],
224
+ to_format=["inchi", "xyz-0"],
225
+ from_format=[None, "mol-0"],
208
226
  expect_success=False,
209
227
  converter_name=[CONVERTER_OB, CONVERTER_C2X],
210
228
  callback=[MCB(CheckFileStatus(expect_output_exists=False,
@@ -246,12 +264,13 @@ l_all_test_specs.append(Spec(name="Errors in logs - GUI",
246
264
 
247
265
  l_all_test_specs.append(Spec(name="Failed conversion - invalid conversion",
248
266
  filename=["Fapatite.ins", "nacl.mol"],
267
+ from_format=["ins", "mol-0"],
249
268
  to_format=["cml", "xyz"],
250
269
  expect_success=False,
251
- converter_name=[CONVERTER_OB, CONVERTER_ATO],
270
+ converter_name=[CONVERTER_C2X, CONVERTER_ATO],
252
271
  callback=MCB(CheckFileStatus(expect_output_exists=False,
253
272
  expect_log_exists=None),
254
- CheckException(ex_type=FileConverterHelpException,
273
+ CheckException(ex_type=FileConverterDatabaseException,
255
274
  ex_message="is not supported")),
256
275
  compatible_with_gui=False,
257
276
  ))
@@ -263,7 +282,8 @@ Not compatible with the GUI, since the GUI only offers valid conversions.
263
282
  l_all_test_specs.append(Spec(name="Blocked conversion - wrong input type",
264
283
  filename="1NE6.mmcif",
265
284
  to_format="cif",
266
- conversion_kwargs={"from_format": "pdb", "strict": True},
285
+ from_format="pdb-0",
286
+ conversion_kwargs={"strict": True},
267
287
  expect_success=False,
268
288
  callback=MCB(CheckFileStatus(expect_output_exists=False,
269
289
  expect_log_exists=None),
@@ -278,7 +298,8 @@ l_all_test_specs.append(Spec(name="Blocked conversion - wrong input type",
278
298
  l_all_test_specs.append(Spec(name="Failed conversion - wrong input type",
279
299
  filename="1NE6.mmcif",
280
300
  to_format="cif",
281
- conversion_kwargs={"from_format": "pdb", "strict": False},
301
+ from_format="pdb-0",
302
+ conversion_kwargs={"strict": False},
282
303
  expect_success=False,
283
304
  callback=MCB(CheckFileStatus(expect_output_exists=False,
284
305
  expect_log_exists=None),
@@ -291,6 +312,8 @@ l_all_test_specs.append(Spec(name="Large files - Library and CLA",
291
312
  filename=["ch3cl-esp.cub", "benzyne.molden", "periodic_dmol3.outmol",
292
313
  "fullRhinovirus.pdb"],
293
314
  to_format=["cdjson", "dmol", "mol", "cif"],
315
+ from_format=[None, None, None, "pdb-0"],
316
+ conversion_kwargs=[{}, {}, {}, {"strict": False}],
294
317
  converter_name=[CONVERTER_OB, CONVERTER_OB, CONVERTER_OB, CONVERTER_C2X],
295
318
  callback=CheckFileStatus(),
296
319
  compatible_with_gui=False,
@@ -301,6 +324,7 @@ l_all_test_specs.append(Spec(name="Large files - GUI",
301
324
  filename=["ch3cl-esp.cub", "benzyne.molden",
302
325
  "periodic_dmol3.outmol", "fullRhinovirus.pdb"],
303
326
  to_format=["cdjson", "dmol", "mol", "cif"],
327
+ from_format=[None, None, None, "pdb-0"],
304
328
  converter_name=[CONVERTER_OB, CONVERTER_OB, CONVERTER_OB, CONVERTER_C2X],
305
329
  expect_success=[False, False, False, True],
306
330
  callback=[CheckException(ex_type=FileConverterInputException),
@@ -319,7 +343,7 @@ max_size_callback = MCB(CheckFileStatus(expect_output_exists=False),
319
343
  ex_status_code=const.STATUS_CODE_SIZE))
320
344
  l_all_test_specs.append(Spec(name="Max size exceeded",
321
345
  filename=["1NE6.mmcif", "caffeine-smi.tar.gz"],
322
- to_format="pdb",
346
+ to_format="pdb-0",
323
347
  conversion_kwargs=[{"max_file_size": 0.0001}, {"max_file_size": 0.0005}],
324
348
  expect_success=False,
325
349
  callback=max_size_callback,