psdi-data-conversion 0.0.38__py3-none-any.whl → 0.1.0__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.
- psdi_data_conversion/app.py +93 -33
- psdi_data_conversion/constants.py +1 -0
- psdi_data_conversion/converter.py +145 -17
- psdi_data_conversion/converters/base.py +24 -20
- psdi_data_conversion/converters/c2x.py +13 -0
- psdi_data_conversion/converters/openbabel.py +2 -1
- psdi_data_conversion/database.py +46 -14
- psdi_data_conversion/dist.py +2 -1
- psdi_data_conversion/file_io.py +1 -2
- psdi_data_conversion/log_utility.py +1 -1
- psdi_data_conversion/main.py +32 -25
- psdi_data_conversion/static/content/index-versions/psdi-common-footer.html +13 -9
- psdi_data_conversion/static/content/index-versions/psdi-common-header.html +1 -1
- psdi_data_conversion/static/content/psdi-common-footer.html +13 -9
- psdi_data_conversion/static/content/psdi-common-header.html +1 -1
- psdi_data_conversion/static/data/data.json +617 -3
- psdi_data_conversion/static/javascript/convert.js +54 -6
- psdi_data_conversion/static/javascript/convert_common.js +16 -2
- psdi_data_conversion/static/javascript/data.js +18 -0
- psdi_data_conversion/static/styles/format.css +7 -0
- psdi_data_conversion/templates/index.htm +8 -9
- psdi_data_conversion/testing/conversion_callbacks.py +2 -2
- psdi_data_conversion/testing/conversion_test_specs.py +27 -7
- psdi_data_conversion/testing/gui.py +18 -12
- psdi_data_conversion/testing/utils.py +3 -3
- psdi_data_conversion/utils.py +21 -0
- {psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/METADATA +2 -2
- {psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/RECORD +31 -30
- {psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/WHEEL +0 -0
- {psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/entry_points.txt +0 -0
- {psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.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 {
|
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
|
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
|
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
|
-
|
107
|
-
|
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
|
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
|
/**
|
@@ -63,6 +63,24 @@ export async function getOutputFormats() {
|
|
63
63
|
return outFormats.sort((a, b) => compare([a.extension, b.extension], [a.note, b.note]))
|
64
64
|
}
|
65
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
|
+
|
66
84
|
export async function getOutputFormatsForInputFormat(inExtension, inNote) {
|
67
85
|
|
68
86
|
const inputFormat = (data.formats.filter(format => (format.extension === inExtension) && (format.note === inNote)))[0];
|
@@ -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
|
@@ -20,13 +20,12 @@
|
|
20
20
|
crossorigin="anonymous"></script>
|
21
21
|
<script src="https://cdn.jsdelivr.net/jquery.dirtyforms/2.0.0/jquery.dirtyforms.min.js"></script>
|
22
22
|
|
23
|
-
{% for item in data %}
|
24
23
|
<script>
|
25
|
-
const token = "{{
|
26
|
-
const max_file_size = "{{
|
27
|
-
const max_file_size_ob = "{{
|
28
|
-
const service_mode = "{{
|
29
|
-
const production_mode = "{{
|
24
|
+
const token = "{{token}}";
|
25
|
+
const max_file_size = "{{max_file_size}}";
|
26
|
+
const max_file_size_ob = "{{max_file_size_ob}}";
|
27
|
+
const service_mode = "{{service_mode}}";
|
28
|
+
const production_mode = "{{production_mode}}";
|
30
29
|
document.documentElement.setAttribute("service-mode", service_mode);
|
31
30
|
document.documentElement.setAttribute("production-mode", production_mode);
|
32
31
|
</script>
|
@@ -121,11 +120,11 @@
|
|
121
120
|
<div class="medGap"></div>
|
122
121
|
</div>
|
123
122
|
</form>
|
124
|
-
|
123
|
+
{% if sha %}
|
125
124
|
<div class="secondary prod-only">
|
126
|
-
<div class="max-width-box">SHA: {{
|
125
|
+
<div class="max-width-box">SHA: {{ sha }}</div>
|
127
126
|
</div>
|
128
|
-
{%
|
127
|
+
{% endif %}
|
129
128
|
<script src="{{url_for('static', filename='/javascript/format.js')}}" type="module" language="JavaScript"></script>
|
130
129
|
|
131
130
|
<footer class="footer" id="psdi-footer"></footer>
|
@@ -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
|
@@ -13,10 +13,11 @@ from psdi_data_conversion.converters.base import (FileConverterAbortException, F
|
|
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
15
|
from psdi_data_conversion.database import FileConverterDatabaseException
|
16
|
-
from psdi_data_conversion.testing.conversion_callbacks import (CheckArchiveContents, CheckException,
|
17
|
-
|
16
|
+
from psdi_data_conversion.testing.conversion_callbacks import (CheckArchiveContents, CheckException, CheckFileStatus,
|
17
|
+
CheckLogContents, CheckLogContentsSuccess,
|
18
18
|
CheckStderrContents, CheckStdoutContents,
|
19
|
-
MatchOutputFile
|
19
|
+
MatchOutputFile)
|
20
|
+
from psdi_data_conversion.testing.conversion_callbacks import MultiCallback as MCB
|
20
21
|
from psdi_data_conversion.testing.utils import ConversionTestSpec as Spec
|
21
22
|
|
22
23
|
l_all_test_specs: list[Spec] = []
|
@@ -29,7 +30,9 @@ l_all_test_specs.append(Spec(name="Standard Single Test",
|
|
29
30
|
CheckLogContentsSuccess(),
|
30
31
|
MatchOutputFile("standard_test.inchi")),
|
31
32
|
))
|
33
|
+
"""A quick single test, functioning mostly as a smoke test for things going right in the simplest case"""
|
32
34
|
|
35
|
+
simple_success_callback = MCB(CheckFileStatus(), CheckLogContentsSuccess())
|
33
36
|
l_all_test_specs.append(Spec(name="Standard Multiple Tests",
|
34
37
|
filename=["1NE6.mmcif",
|
35
38
|
"hemoglobin.pdb", "aceticacid.mol", "nacl.cif",
|
@@ -39,7 +42,7 @@ l_all_test_specs.append(Spec(name="Standard Multiple Tests",
|
|
39
42
|
to_format=["pdb-0",
|
40
43
|
"cif", "mol2", "xyz",
|
41
44
|
"cif", "xyz", "xyz",
|
42
|
-
"cif", "xyz", "xyz",
|
45
|
+
"cif", "xyz-0", "xyz-0",
|
43
46
|
"cml"],
|
44
47
|
from_format=[None,
|
45
48
|
None, None, None,
|
@@ -51,12 +54,29 @@ l_all_test_specs.append(Spec(name="Standard Multiple Tests",
|
|
51
54
|
CONVERTER_ATO, CONVERTER_ATO, CONVERTER_ATO,
|
52
55
|
CONVERTER_C2X, CONVERTER_C2X, CONVERTER_C2X,
|
53
56
|
CONVERTER_OB],
|
54
|
-
callback=
|
55
|
-
CheckLogContentsSuccess()),
|
57
|
+
callback=simple_success_callback,
|
56
58
|
))
|
57
59
|
"""A basic set of test conversions which we expect to succeed without issue, running conversions with each of the
|
58
60
|
Open Babel, Atomsk, and c2x converters"""
|
59
61
|
|
62
|
+
l_all_test_specs.append(Spec(name="c2x Formats Tests",
|
63
|
+
to_format=["res", "abi", "POSCAR", "cml"],
|
64
|
+
converter_name=CONVERTER_C2X,
|
65
|
+
callback=simple_success_callback,
|
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
|
+
|
72
|
+
l_all_test_specs.append(Spec(name="Converter Name Sensitivity Tests",
|
73
|
+
converter_name=["open babel", "oPeNbaBEL", "C2X", "atomsk"],
|
74
|
+
to_format="xyz-0",
|
75
|
+
callback=simple_success_callback,
|
76
|
+
compatible_with_gui=False,
|
77
|
+
))
|
78
|
+
"""Tests that converters can be specified case- and space-insensitively in the library and CLI"""
|
79
|
+
|
60
80
|
archive_callback = MCB(CheckFileStatus(),
|
61
81
|
CheckArchiveContents(l_filename_bases=["caffeine-no-flags",
|
62
82
|
"caffeine-ia",
|
@@ -209,7 +229,7 @@ Not compatible with the GUI, since the GUI can't forcibly delete files uploaded
|
|
209
229
|
|
210
230
|
l_all_test_specs.append(Spec(name="Failed conversion - bad input file",
|
211
231
|
filename=["quartz_err.xyz", "cyclopropane_err.mol"],
|
212
|
-
to_format=["inchi", "xyz"],
|
232
|
+
to_format=["inchi", "xyz-0"],
|
213
233
|
from_format=[None, "mol-0"],
|
214
234
|
expect_success=False,
|
215
235
|
converter_name=[CONVERTER_OB, CONVERTER_C2X],
|
@@ -6,10 +6,10 @@ Utilities to aid in testing of the GUI
|
|
6
6
|
|
7
7
|
import os
|
8
8
|
import shutil
|
9
|
-
from tempfile import TemporaryDirectory
|
10
|
-
|
11
9
|
import time
|
12
10
|
from dataclasses import dataclass
|
11
|
+
from tempfile import TemporaryDirectory
|
12
|
+
|
13
13
|
import pytest
|
14
14
|
from selenium.common.exceptions import TimeoutException
|
15
15
|
from selenium.webdriver.common.alert import Alert
|
@@ -45,6 +45,11 @@ def wait_and_find_element(root: WebDriver | EC.WebElement, xpath: str, by=By.XPA
|
|
45
45
|
return root.find_element(by, xpath)
|
46
46
|
|
47
47
|
|
48
|
+
def wait_for_cover_hidden(root: WebDriver):
|
49
|
+
"""Wait until the page cover is removed"""
|
50
|
+
WebDriverWait(root, TIMEOUT).until(EC.invisibility_of_element((By.XPATH, "//div[@id='cover']")))
|
51
|
+
|
52
|
+
|
48
53
|
@dataclass
|
49
54
|
class GuiTestSpecRunner():
|
50
55
|
"""Class which provides an interface to run test conversions through the GUI
|
@@ -253,25 +258,30 @@ class GuiSingleTestSpecRunner:
|
|
253
258
|
4. Click the "Yes" button to confirm and go to the convert page
|
254
259
|
"""
|
255
260
|
|
256
|
-
# Get the homepage
|
261
|
+
# Get the homepage and wait for the cover to be removed
|
257
262
|
self.driver.get(f"{self.origin}/")
|
263
|
+
wait_for_cover_hidden(self.driver)
|
258
264
|
|
259
265
|
wait_for_element(self.driver, "//select[@id='fromList']/option")
|
260
266
|
|
261
267
|
# Select from_format from the 'from' list.
|
268
|
+
full_from_format = f"{self._from_format_info.name}: {self._from_format_info.note}"
|
262
269
|
self.driver.find_element(
|
263
|
-
By.XPATH, f"//select[@id='fromList']/option[starts-with(.,'{
|
270
|
+
By.XPATH, f"//select[@id='fromList']/option[starts-with(.,'{full_from_format}')]").click()
|
264
271
|
|
265
272
|
# Select to_format from the 'to' list.
|
273
|
+
full_to_format = f"{self._to_format_info.name}: {self._to_format_info.note}"
|
266
274
|
self.driver.find_element(
|
267
|
-
By.XPATH, f"//select[@id='toList']/option[starts-with(.,'{
|
275
|
+
By.XPATH, f"//select[@id='toList']/option[starts-with(.,'{full_to_format}')]").click()
|
268
276
|
|
269
277
|
# Select converter from the available conversion options list.
|
270
278
|
self.driver.find_element(
|
271
279
|
By.XPATH, f"//select[@id='success']/option[contains(.,'{self.single_test_spec.converter_name}')]").click()
|
272
280
|
|
273
|
-
# Click on the "Yes" button to accept the converter and go to the conversion page
|
281
|
+
# Click on the "Yes" button to accept the converter and go to the conversion page, and wait for the cover to be
|
282
|
+
# removed there
|
274
283
|
self.driver.find_element(By.XPATH, "//input[@id='yesButton']").click()
|
284
|
+
wait_for_cover_hidden(self.driver)
|
275
285
|
|
276
286
|
def _set_conversion_settings(self):
|
277
287
|
"""Set settings on the convert page appropriately for the desired conversion
|
@@ -315,13 +325,11 @@ class GuiSingleTestSpecRunner:
|
|
315
325
|
continue
|
316
326
|
flags_select = Select(wait_and_find_element(self.driver, f"//select[@id='{select_id}']"))
|
317
327
|
for flag in l_flags:
|
318
|
-
found = False
|
319
328
|
for option in flags_select.options:
|
320
329
|
if option.text.startswith(f"{flag}:"):
|
321
330
|
flags_select.select_by_visible_text(option.text)
|
322
|
-
found = True
|
323
331
|
break
|
324
|
-
|
332
|
+
else:
|
325
333
|
raise ValueError(f"Flag {flag} was not found in {select_id} selection box for conversion from "
|
326
334
|
f"{self._from_format_info.name} to {self._to_format_info.name} with "
|
327
335
|
f"converter {self.single_test_spec.converter_name}")
|
@@ -343,7 +351,6 @@ class GuiSingleTestSpecRunner:
|
|
343
351
|
|
344
352
|
# Look for and set each option
|
345
353
|
for option in l_options:
|
346
|
-
found = False
|
347
354
|
for row in l_rows:
|
348
355
|
l_items = row.find_elements(By.XPATH, "./td")
|
349
356
|
label = l_items[1]
|
@@ -357,10 +364,9 @@ class GuiSingleTestSpecRunner:
|
|
357
364
|
input_box = wait_and_find_element(l_items[2], "./input")
|
358
365
|
input_box.send_keys(option[1:])
|
359
366
|
|
360
|
-
found = True
|
361
367
|
break
|
362
368
|
|
363
|
-
|
369
|
+
else:
|
364
370
|
raise ValueError(f"Option {option} was not found in {table_id} options table for conversion from "
|
365
371
|
f"{self._from_format_info.name} to {self._to_format_info.name} with "
|
366
372
|
f"converter {self.single_test_spec.converter_name}")
|
@@ -6,12 +6,12 @@ This module defines general classes and methods used for unit tests.
|
|
6
6
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
9
|
-
from dataclasses import dataclass, field
|
10
|
-
from collections.abc import Callable, Iterable
|
11
|
-
from math import isclose
|
12
9
|
import os
|
13
10
|
import shlex
|
14
11
|
import sys
|
12
|
+
from collections.abc import Callable, Iterable
|
13
|
+
from dataclasses import dataclass, field
|
14
|
+
from math import isclose
|
15
15
|
from tempfile import TemporaryDirectory
|
16
16
|
from typing import Any
|
17
17
|
from unittest.mock import patch
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"""
|
2
|
+
# utils.py
|
3
|
+
|
4
|
+
Miscellaneous utility functions used by this project
|
5
|
+
"""
|
6
|
+
|
7
|
+
|
8
|
+
def regularize_name(name: str):
|
9
|
+
"""Regularizes a name for comparisons, making it lowercase and stripping spaces
|
10
|
+
|
11
|
+
Parameters
|
12
|
+
----------
|
13
|
+
name : str
|
14
|
+
The name, e.g. "Open Babel"
|
15
|
+
|
16
|
+
Returns
|
17
|
+
-------
|
18
|
+
str
|
19
|
+
The regularized name, e.g. "openbabel"
|
20
|
+
"""
|
21
|
+
return name.lower().replace(" ", "")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: psdi_data_conversion
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.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/
|
@@ -243,7 +243,7 @@ Description-Content-Type: text/markdown
|
|
243
243
|
|
244
244
|
# PSDI Data Conversion
|
245
245
|
|
246
|
-
|
246
|
+
Release date: 2024-04-29
|
247
247
|
|
248
248
|
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:
|
249
249
|
|
@@ -1,13 +1,14 @@
|
|
1
1
|
psdi_data_conversion/__init__.py,sha256=urMsTqsTHTch1q4rMT9dgGnrvdPFMP9B8r-6Kr8H5sE,404
|
2
|
-
psdi_data_conversion/app.py,sha256=
|
3
|
-
psdi_data_conversion/constants.py,sha256=
|
4
|
-
psdi_data_conversion/converter.py,sha256=
|
5
|
-
psdi_data_conversion/database.py,sha256=
|
6
|
-
psdi_data_conversion/dist.py,sha256=
|
7
|
-
psdi_data_conversion/file_io.py,sha256=
|
8
|
-
psdi_data_conversion/log_utility.py,sha256=
|
9
|
-
psdi_data_conversion/main.py,sha256=
|
2
|
+
psdi_data_conversion/app.py,sha256=DCY5TLLYdCj-r9GH-SKXvwtWm9AcQJ0SJbCsefl3K94,15738
|
3
|
+
psdi_data_conversion/constants.py,sha256=Hq2OVbcSkcv6T87-YJlo1PVlr9ILlB4H3E9JYjzvCF4,7423
|
4
|
+
psdi_data_conversion/converter.py,sha256=Y77mqH2OKxf2YelphWDl82AKoRa-APle-l3e8wG_WZA,27315
|
5
|
+
psdi_data_conversion/database.py,sha256=XzKvtT-cFmKLWLo5OBB5CV_rGHuqEEuENNyZnbS39qE,56419
|
6
|
+
psdi_data_conversion/dist.py,sha256=LOcKEP7H7JA9teX1m-5awuBi69gmdhtUit7yxtCTOZ8,2293
|
7
|
+
psdi_data_conversion/file_io.py,sha256=LvdPmnYL_7Xlcr-7LJjUbbky4gKiqTTvPRzdbtvQaJo,8794
|
8
|
+
psdi_data_conversion/log_utility.py,sha256=CHAq-JvBnTKaE0SHK5hM5j2dTbfSli4iUc3hsf6dBhc,8789
|
9
|
+
psdi_data_conversion/main.py,sha256=9Gu3CxbUfMuDxyNBx_-kQwWB4eOTWRHGmxCsVnpdbvs,42421
|
10
10
|
psdi_data_conversion/security.py,sha256=wjdrMre29TpkF2NqrsXJ5sschSAnDzqLYTLUcNR21Qw,902
|
11
|
+
psdi_data_conversion/utils.py,sha256=iTjNfrD4n_hU9h20ldYrX2Bmp5KhCBIeMSUMLtPZ_8k,402
|
11
12
|
psdi_data_conversion/bin/LICENSE_ATOMSK,sha256=-Ay6SFTAf9x-OaRAiOgMNoutfUMLHx5jQQA1HqZ6p7I,34886
|
12
13
|
psdi_data_conversion/bin/LICENSE_C2X,sha256=-Ay6SFTAf9x-OaRAiOgMNoutfUMLHx5jQQA1HqZ6p7I,34886
|
13
14
|
psdi_data_conversion/bin/linux/atomsk,sha256=GDsG1MlEvmk_XPspadzEzuil6N775iewDvNZS6rWJWk,34104032
|
@@ -16,9 +17,9 @@ psdi_data_conversion/bin/mac/atomsk,sha256=pqExRdkR8NSqSasHZjE74R_CiM6Dkr_yvfyak
|
|
16
17
|
psdi_data_conversion/bin/mac/c2x,sha256=dI-bBoQ6uqc6KMYKJaq0x7ejJgOf_wysTxQA5BrF8AY,2581960
|
17
18
|
psdi_data_conversion/converters/__init__.py,sha256=15Ldt06eyZ0bgNPB4qg419U0Zcjt6TUCTzjCBo8EIzM,210
|
18
19
|
psdi_data_conversion/converters/atomsk.py,sha256=_V33me1e4HW0-YXvdE-z6PdwtSK2gYV6QZf5d8aPqH4,1523
|
19
|
-
psdi_data_conversion/converters/base.py,sha256=
|
20
|
-
psdi_data_conversion/converters/c2x.py,sha256=
|
21
|
-
psdi_data_conversion/converters/openbabel.py,sha256=
|
20
|
+
psdi_data_conversion/converters/base.py,sha256=gYZ-2f693_YBgJdlXFUZOpjVhB8PAbkbLFkOS9BFg9Q,36022
|
21
|
+
psdi_data_conversion/converters/c2x.py,sha256=jDA84H8Jpz--ajTWNWX6K6oMfOMMbMxkA31-VnGi0gU,2019
|
22
|
+
psdi_data_conversion/converters/openbabel.py,sha256=OYppOMfnvxmVgRY5vUkcVokWn-bQSSeG8MOFqN1MCIY,13224
|
22
23
|
psdi_data_conversion/scripts/atomsk.sh,sha256=N_NMO5q8sI3Lt1TerC-xcKbMI0kfscAudy5UAbY0uR0,804
|
23
24
|
psdi_data_conversion/scripts/c2x.sh,sha256=F48jhgtgouKKZDQ9p6tCCNBN5bPuidBq2GcTurdWzQc,770
|
24
25
|
psdi_data_conversion/static/content/accessibility.htm,sha256=5mzlPM-d5KBoOuvuBTmer5QEI9lWQSd7FPH1KFn_7B0,14187
|
@@ -29,13 +30,13 @@ psdi_data_conversion/static/content/documentation.htm,sha256=1GiEjlDCP0kJ3CKkx3l
|
|
29
30
|
psdi_data_conversion/static/content/download.htm,sha256=DQKWEuq_Bjv2TyV6DnPXnHrSOBvGYRHOU-m6YOwfsh4,4727
|
30
31
|
psdi_data_conversion/static/content/feedback.htm,sha256=fZrhn4Egs9g6ygqPzV6ZG9ndYK02VdALNVNXRsZ716k,1788
|
31
32
|
psdi_data_conversion/static/content/header-links.html,sha256=7B2bHa7dLfSZ4hPMvVJ3kR0niVAOO3FtHJo0K6m1oP4,693
|
32
|
-
psdi_data_conversion/static/content/psdi-common-footer.html,sha256=
|
33
|
-
psdi_data_conversion/static/content/psdi-common-header.html,sha256=
|
33
|
+
psdi_data_conversion/static/content/psdi-common-footer.html,sha256=3_KqTtwtkvCvi52LcRrN7oVfMfFdHqrHc39gMrYzGxg,4070
|
34
|
+
psdi_data_conversion/static/content/psdi-common-header.html,sha256=2upXPOZ-EM6Bv7ltPJnynPBjYz4Z27sNl4LuUaVdVjM,1815
|
34
35
|
psdi_data_conversion/static/content/report.htm,sha256=CRwlF7a7QvAjHsajuehWOtLxbo-JAjqrS_Q-I4BWxzs,4549
|
35
36
|
psdi_data_conversion/static/content/index-versions/header-links.html,sha256=WN9oZL7hLtH_yv5PvX3Ky7_YGrNvQL_RQ5eU8DB50Rg,764
|
36
|
-
psdi_data_conversion/static/content/index-versions/psdi-common-footer.html,sha256=
|
37
|
-
psdi_data_conversion/static/content/index-versions/psdi-common-header.html,sha256=
|
38
|
-
psdi_data_conversion/static/data/data.json,sha256=
|
37
|
+
psdi_data_conversion/static/content/index-versions/psdi-common-footer.html,sha256=APBMI9c5-4fNV-CCYEs9ySgAahc7u1w-0e3EjM1MiD8,4126
|
38
|
+
psdi_data_conversion/static/content/index-versions/psdi-common-header.html,sha256=w6Q_uu0W4MdioVoh6w0Cy4m2ACr7xAnampx1TfPvT9M,1897
|
39
|
+
psdi_data_conversion/static/data/data.json,sha256=1nljosxtwbLRfIIIa6-GHJnhvzhB759oEGvVQ18QP_4,3647095
|
39
40
|
psdi_data_conversion/static/img/colormode-toggle-dm.svg,sha256=Q85ODwU67chZ77lyT9gITtnmqzJEycFmz35dJuqaPXE,502
|
40
41
|
psdi_data_conversion/static/img/colormode-toggle-lm.svg,sha256=sIKXsNmLIXU4fSuuqrN0r-J4Hd3NIqoiXNT3mdq5-Fo,1155
|
41
42
|
psdi_data_conversion/static/img/psdi-icon-dark.svg,sha256=-hYXxegsw67i0qqAOYCx-I-ZPyG04wG0aBVTKoZQlL0,69747
|
@@ -62,26 +63,26 @@ psdi_data_conversion/static/img/ukri-logo-darktext.png,sha256=3UgghERAmFdnre0Ffc
|
|
62
63
|
psdi_data_conversion/static/img/ukri-logo-lighttext.png,sha256=ptIQwIGGdVsO2rTximo9QjtJFH9DpkJcAs1glwKFjwo,25579
|
63
64
|
psdi_data_conversion/static/javascript/accessibility.js,sha256=kbnWHeBNPrTLrnYRjMEUmiOcCXM2bORYIRfzUB03TAE,7208
|
64
65
|
psdi_data_conversion/static/javascript/common.js,sha256=3YZdwfq54OPl-xIImTwjbXqxKqlrAaEbeac0cAHvScU,1720
|
65
|
-
psdi_data_conversion/static/javascript/convert.js,sha256=
|
66
|
-
psdi_data_conversion/static/javascript/convert_common.js,sha256=
|
66
|
+
psdi_data_conversion/static/javascript/convert.js,sha256=xWd0V9wyPD6t2ltTbaAQqqnvneU6_VEdMhVyg7UUo6c,10453
|
67
|
+
psdi_data_conversion/static/javascript/convert_common.js,sha256=nr0UTAPv2hahqCjl_JzxoOAtsyKIsk6qDXO6cItmChg,11369
|
67
68
|
psdi_data_conversion/static/javascript/convertato.js,sha256=faSvfm9HWT3i8piqEDq8OfekiPo3jCV2vKT_VjdzwmE,3555
|
68
69
|
psdi_data_conversion/static/javascript/convertc2x.js,sha256=TTqC9B2FD_q3RcPE2GJh6yAhocQyJLRfQsbSWzm2g3U,3550
|
69
|
-
psdi_data_conversion/static/javascript/data.js,sha256=
|
70
|
+
psdi_data_conversion/static/javascript/data.js,sha256=ZM5PkPqiq8aUaB0ARWLK4TVSuxJKAFAAxlF1-7BsJ1g,6915
|
70
71
|
psdi_data_conversion/static/javascript/format.js,sha256=S-ovNuqOSfS-RYDhFxxCDpTKFKdxOWAYvJuzeEPcXB0,21260
|
71
72
|
psdi_data_conversion/static/javascript/load_accessibility.js,sha256=jTLfmubEmko2bJ_MKWMkmYxUeBxotozc-0-ua69CYJo,3265
|
72
73
|
psdi_data_conversion/static/javascript/psdi-common.js,sha256=I0QqGQ7l_rA4KEfenQTfPc-uOXXp8sxMh_NHL3EkFm4,6231
|
73
74
|
psdi_data_conversion/static/javascript/report.js,sha256=BHH5UOhXJtB6J_xk_y6woquNKt5W9hCrQapxKtGG1eA,12470
|
74
|
-
psdi_data_conversion/static/styles/format.css,sha256=
|
75
|
+
psdi_data_conversion/static/styles/format.css,sha256=PaQkUVxQfXI9nbJ-7YsN1tNIcLXfwXk8wJC-zht8nRA,3269
|
75
76
|
psdi_data_conversion/static/styles/psdi-common.css,sha256=09VY-lldoZCrohuqPKnd9fvDget5g9ybi6uh13pYeY0,17249
|
76
|
-
psdi_data_conversion/templates/index.htm,sha256=
|
77
|
+
psdi_data_conversion/templates/index.htm,sha256=oZEJNc1aenHExnUZMv6XJfn7nibtYevGGpOaeRbIZ2Y,6784
|
77
78
|
psdi_data_conversion/testing/__init__.py,sha256=Xku7drtLTYLLPsd403eC0LIEa_iohVifyeyAITy2w7U,135
|
78
79
|
psdi_data_conversion/testing/constants.py,sha256=BtIafruSobZ9cFY0VW5Bu209eiftnN8b3ObouZBrFQU,521
|
79
|
-
psdi_data_conversion/testing/conversion_callbacks.py,sha256=
|
80
|
-
psdi_data_conversion/testing/conversion_test_specs.py,sha256=
|
81
|
-
psdi_data_conversion/testing/gui.py,sha256=
|
82
|
-
psdi_data_conversion/testing/utils.py,sha256=
|
83
|
-
psdi_data_conversion-0.0.
|
84
|
-
psdi_data_conversion-0.0.
|
85
|
-
psdi_data_conversion-0.0.
|
86
|
-
psdi_data_conversion-0.0.
|
87
|
-
psdi_data_conversion-0.0.
|
80
|
+
psdi_data_conversion/testing/conversion_callbacks.py,sha256=ATR-_BsYCUN8KyOyUjfdWCELzySxLN5jOI0JyrQnmHQ,18858
|
81
|
+
psdi_data_conversion/testing/conversion_test_specs.py,sha256=8W97tI6dVbHE9BEW76dsKDlfsm5oTlrlntG--b0h8HU,26106
|
82
|
+
psdi_data_conversion/testing/gui.py,sha256=ul7ixYANIzmOG2ZNOZmQO6wsHmGHdiBGAlw-KuoN0j8,19085
|
83
|
+
psdi_data_conversion/testing/utils.py,sha256=YrFxjyiIx1seph0j7jCUgAVm6HvXY9QJjx0MvNJRbfw,26134
|
84
|
+
psdi_data_conversion-0.1.0.dist-info/METADATA,sha256=mD4CvjwfelhGA25tGlYa2XUqQyzwycNCod3r7SD052Q,48108
|
85
|
+
psdi_data_conversion-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
86
|
+
psdi_data_conversion-0.1.0.dist-info/entry_points.txt,sha256=xL7XTzaPRr2E67WhOD1M1Q-76hB8ausQlnNiHzuZQPA,123
|
87
|
+
psdi_data_conversion-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
88
|
+
psdi_data_conversion-0.1.0.dist-info/RECORD,,
|
File without changes
|
{psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{psdi_data_conversion-0.0.38.dist-info → psdi_data_conversion-0.1.0.dist-info}/licenses/LICENSE
RENAMED
File without changes
|