psdi-data-conversion 0.0.33__py3-none-any.whl → 0.0.36__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 (36) hide show
  1. psdi_data_conversion/app.py +23 -3
  2. psdi_data_conversion/constants.py +2 -0
  3. psdi_data_conversion/converter.py +16 -6
  4. psdi_data_conversion/converters/atomsk.py +3 -1
  5. psdi_data_conversion/converters/base.py +99 -39
  6. psdi_data_conversion/converters/c2x.py +3 -1
  7. psdi_data_conversion/converters/openbabel.py +40 -1
  8. psdi_data_conversion/database.py +5 -0
  9. psdi_data_conversion/main.py +18 -10
  10. psdi_data_conversion/static/content/accessibility.htm +5 -5
  11. psdi_data_conversion/static/content/convert.htm +31 -15
  12. psdi_data_conversion/static/content/convertato.htm +46 -28
  13. psdi_data_conversion/static/content/convertc2x.htm +47 -28
  14. psdi_data_conversion/static/content/documentation.htm +4 -4
  15. psdi_data_conversion/static/content/download.htm +4 -1
  16. psdi_data_conversion/static/content/feedback.htm +4 -4
  17. psdi_data_conversion/static/content/index-versions/psdi-common-header.html +1 -1
  18. psdi_data_conversion/static/content/psdi-common-header.html +1 -1
  19. psdi_data_conversion/static/content/report.htm +9 -7
  20. psdi_data_conversion/static/javascript/common.js +20 -0
  21. psdi_data_conversion/static/javascript/convert.js +1 -2
  22. psdi_data_conversion/static/javascript/convert_common.js +100 -7
  23. psdi_data_conversion/static/javascript/convertato.js +1 -2
  24. psdi_data_conversion/static/javascript/convertc2x.js +1 -2
  25. psdi_data_conversion/static/javascript/format.js +12 -0
  26. psdi_data_conversion/static/javascript/report.js +6 -0
  27. psdi_data_conversion/static/styles/format.css +13 -0
  28. psdi_data_conversion/static/styles/psdi-common.css +5 -2
  29. psdi_data_conversion/templates/index.htm +4 -1
  30. psdi_data_conversion/testing/conversion_test_specs.py +240 -149
  31. psdi_data_conversion/testing/utils.py +22 -7
  32. {psdi_data_conversion-0.0.33.dist-info → psdi_data_conversion-0.0.36.dist-info}/METADATA +29 -6
  33. {psdi_data_conversion-0.0.33.dist-info → psdi_data_conversion-0.0.36.dist-info}/RECORD +36 -36
  34. {psdi_data_conversion-0.0.33.dist-info → psdi_data_conversion-0.0.36.dist-info}/WHEEL +0 -0
  35. {psdi_data_conversion-0.0.33.dist-info → psdi_data_conversion-0.0.36.dist-info}/entry_points.txt +0 -0
  36. {psdi_data_conversion-0.0.33.dist-info → psdi_data_conversion-0.0.36.dist-info}/licenses/LICENSE +0 -0
@@ -15,194 +15,285 @@ from psdi_data_conversion.converters.openbabel import CONVERTER_OB, COORD_GEN_KE
15
15
  from psdi_data_conversion.testing.conversion_callbacks import (CheckArchiveContents, CheckException, CheckLogContents,
16
16
  CheckLogContentsSuccess, CheckFileStatus,
17
17
  CheckStderrContents, CheckStdoutContents,
18
- MatchOutputFile, MultiCallback)
19
- from psdi_data_conversion.testing.utils import ConversionTestSpec
20
-
21
- basic_tests = ConversionTestSpec(filename=["1NE6.mmcif", "standard_test.cdxml",
22
- "hemoglobin.pdb", "nacl.cif",
23
- "hemoglobin.pdb", "nacl.cif",
24
- "hemoglobin.pdb", "nacl.cif"],
25
- to_format=["pdb", "inchi", "cif", "xyz",
26
- "cif", "xyz",
27
- "cif", "xyz"],
28
- name=[CONVERTER_OB, CONVERTER_OB,
29
- CONVERTER_OB, CONVERTER_OB,
30
- CONVERTER_ATO, CONVERTER_ATO,
31
- CONVERTER_C2X, CONVERTER_C2X],
32
- callback=MultiCallback(CheckFileStatus(),
33
- CheckLogContentsSuccess()))
34
- """A basic set of test conversions which we expect to succeed without issue, running two conversions with each of the
18
+ MatchOutputFile, MultiCallback as MCB)
19
+ from psdi_data_conversion.testing.utils import ConversionTestSpec as Spec
20
+
21
+
22
+ l_all_test_specs: list[Spec] = []
23
+ """All test specs defined in this file"""
24
+
25
+ l_all_test_specs.append(Spec(name="Basic",
26
+ filename=["1NE6.mmcif", "standard_test.cdxml",
27
+ "hemoglobin.pdb", "aceticacid.mol", "nacl.cif",
28
+ "hemoglobin.pdb", "hemoglobin.pdb", "nacl.cif",
29
+ "hemoglobin.pdb", "hemoglobin.pdb", "nacl.cif",
30
+ "ethanol.xyz"],
31
+ to_format=["pdb", "inchi",
32
+ "cif", "mol2", "xyz",
33
+ "cif", "xyz", "xyz",
34
+ "cif", "xyz", "xyz",
35
+ "cml"],
36
+ converter_name=[CONVERTER_OB, CONVERTER_OB,
37
+ CONVERTER_OB, CONVERTER_OB, CONVERTER_OB,
38
+ CONVERTER_ATO, CONVERTER_ATO, CONVERTER_ATO,
39
+ CONVERTER_C2X, CONVERTER_C2X, CONVERTER_C2X,
40
+ CONVERTER_OB],
41
+ callback=MCB(CheckFileStatus(),
42
+ CheckLogContentsSuccess()),
43
+ ))
44
+ """A basic set of test conversions which we expect to succeed without issue, running conversions with each of the
35
45
  Open Babel, Atomsk, and c2x converters"""
36
46
 
37
- archive_callback = MultiCallback(CheckFileStatus(),
38
- CheckArchiveContents(l_filename_bases=["caffeine-no-flags",
39
- "caffeine-ia",
40
- "caffeine-ia-ox",
41
- "caffeine-ia-okx",
42
- "caffeine-ia-okx-oof4",
43
- "caffeine-ia-okx-oof4l5",],
44
- to_format="inchi"))
45
- archive_tests = ConversionTestSpec(filename=["caffeine-smi.zip",
46
- "caffeine-smi.tar",
47
- "caffeine-smi.tar.gz"],
48
- to_format="inchi",
49
- callback=archive_callback)
47
+ archive_callback = MCB(CheckFileStatus(),
48
+ CheckArchiveContents(l_filename_bases=["caffeine-no-flags",
49
+ "caffeine-ia",
50
+ "caffeine-ia-ox",
51
+ "caffeine-ia-okx",
52
+ "caffeine-ia-okx-oof4",
53
+ "caffeine-ia-okx-oof4l5",],
54
+ to_format="inchi"))
55
+
56
+ l_all_test_specs.append(Spec(name="Archive",
57
+ filename=["caffeine-smi.zip",
58
+ "caffeine-smi.tar",
59
+ "caffeine-smi.tar.gz"],
60
+ to_format="inchi",
61
+ callback=archive_callback,
62
+ ))
50
63
  """A test of converting a archives of files"""
51
64
 
52
- archive_wrong_format_test = ConversionTestSpec(filename="caffeine-smi.zip",
53
- to_format="inchi",
54
- conversion_kwargs=[{"from_format": "pdb"},
55
- {"from_format": "pdb", "strict": True}],
56
- expect_success=[True, False],
57
- callback=[CheckStderrContents(const.ERR_WRONG_EXTENSIONS),
58
- CheckException(ex_type=FileConverterInputException,
59
- ex_message=const.ERR_WRONG_EXTENSIONS)]
60
- )
65
+ l_all_test_specs.append(Spec(name="Archive (wrong format)",
66
+ filename="caffeine-smi.zip",
67
+ to_format="inchi",
68
+ conversion_kwargs=[{"from_format": "pdb"},
69
+ {"from_format": "pdb", "strict": True}],
70
+ expect_success=[True, False],
71
+ callback=[CheckStderrContents(const.ERR_WRONG_EXTENSIONS),
72
+ CheckException(ex_type=FileConverterInputException,
73
+ ex_message=const.ERR_WRONG_EXTENSIONS)],
74
+ ))
61
75
  """A test that if the user provides the wrong input format for files in an archive, and error will be output to stderr
62
76
  """
63
77
 
64
- log_mode_tests = ConversionTestSpec(conversion_kwargs=[{"log_mode": const.LOG_NONE},
65
- {"log_mode": const.LOG_STDOUT},
66
- {"log_mode": const.LOG_SIMPLE},
67
- {"log_mode": const.LOG_FULL},
68
- {"log_mode": const.LOG_FULL_FORCE},],
69
- callback=[CheckFileStatus(expect_log_exists=False,
70
- expect_global_log_exists=False),
71
- CheckFileStatus(expect_log_exists=False,
72
- expect_global_log_exists=False),
73
- CheckFileStatus(expect_log_exists=True,
74
- expect_global_log_exists=False),
75
- CheckFileStatus(expect_log_exists=True,
76
- expect_global_log_exists=True),
77
- CheckFileStatus(expect_log_exists=True,
78
- expect_global_log_exists=True)],
79
- )
78
+ l_all_test_specs.append(Spec(name="Log mode",
79
+ conversion_kwargs=[{"log_mode": const.LOG_NONE},
80
+ {"log_mode": const.LOG_STDOUT},
81
+ {"log_mode": const.LOG_SIMPLE},
82
+ {"log_mode": const.LOG_FULL},
83
+ {"log_mode": const.LOG_FULL_FORCE},],
84
+ callback=[CheckFileStatus(expect_log_exists=False,
85
+ expect_global_log_exists=False),
86
+ CheckFileStatus(expect_log_exists=False,
87
+ expect_global_log_exists=False),
88
+ CheckFileStatus(expect_log_exists=True,
89
+ expect_global_log_exists=False),
90
+ CheckFileStatus(expect_log_exists=True,
91
+ expect_global_log_exists=True),
92
+ CheckFileStatus(expect_log_exists=True,
93
+ expect_global_log_exists=True)],
94
+ compatible_with_gui=False,
95
+ ))
80
96
  """Tests that the different log modes have the desired effects on logs
81
97
 
82
- NOTE: Not compatible with GUI tests, since the GUI requires the log mode to always be "Full"
98
+ Not compatible with GUI tests, since the GUI requires the log mode to always be "Full"
83
99
  """
84
100
 
85
- stdout_test = ConversionTestSpec(conversion_kwargs={"log_mode": const.LOG_STDOUT},
86
- callback=CheckStdoutContents(l_strings_to_exclude=["ERROR", "exception", "Exception"],
87
- l_regex_to_find=[r"File name:\s*nacl",
88
- const.DATETIME_RE_RAW]
89
- ))
101
+ l_all_test_specs.append(Spec(name="Stdout",
102
+ conversion_kwargs={"log_mode": const.LOG_STDOUT},
103
+ callback=CheckStdoutContents(l_strings_to_exclude=["ERROR", "exception",
104
+ "Exception"],
105
+ l_regex_to_find=[r"File name:\s*nacl",
106
+ const.DATETIME_RE_RAW]
107
+ ),
108
+ compatible_with_gui=False,
109
+ ))
90
110
  """Test that the log is output to stdout when requested
91
111
 
92
- NOTE: Not compatible with GUI tests, since the GUI requires the log mode to always be "Full"
112
+ Not compatible with GUI tests, since the GUI requires the log mode to always be "Full"
93
113
  """
94
114
 
95
- quiet_test = ConversionTestSpec(conversion_kwargs={"log_mode": const.LOG_NONE},
96
- callback=CheckStdoutContents(l_regex_to_exclude=r"."))
115
+ l_all_test_specs.append(Spec(name="Quiet",
116
+ conversion_kwargs={"log_mode": const.LOG_NONE},
117
+ callback=CheckStdoutContents(l_regex_to_exclude=r"."),
118
+ compatible_with_gui=False,
119
+ ))
97
120
  """Test that nothing is output to stdout when quiet mode is enabled
98
121
 
99
- NOTE: Not compatible with GUI tests, since the GUI doesn't support quiet mode
122
+ Not compatible with GUI tests, since the GUI doesn't support quiet mode
100
123
  """
101
124
 
102
- open_babel_warning_test = ConversionTestSpec(filename="1NE6.mmcif",
103
- to_format="pdb",
104
- callback=CheckLogContentsSuccess(["Open Babel Warning",
105
- "Failed to kekulize aromatic bonds",])
106
- )
125
+ l_all_test_specs.append(Spec(name="Open Babel Warning",
126
+ filename="1NE6.mmcif",
127
+ to_format="pdb",
128
+ callback=CheckLogContentsSuccess(["Open Babel Warning",
129
+ "Failed to kekulize aromatic bonds",])
130
+ ))
107
131
  """A test that confirms expected warnings form Open Babel are output and captured in the log"""
108
132
 
109
- invalid_converter_callback = MultiCallback(CheckFileStatus(expect_output_exists=False,
110
- expect_log_exists=False),
111
- CheckException(ex_type=FileConverterInputException,
112
- ex_message="Converter {} not recognized"))
113
- invalid_converter_test = ConversionTestSpec(name="INVALID",
114
- expect_success=False,
115
- callback=invalid_converter_callback)
133
+ invalid_converter_callback = MCB(CheckFileStatus(expect_output_exists=False,
134
+ expect_log_exists=False),
135
+ CheckException(ex_type=FileConverterInputException,
136
+ ex_message="Converter {} not recognized"))
137
+ l_all_test_specs.append(Spec(name="Invalid Converter",
138
+ converter_name="INVALID",
139
+ expect_success=False,
140
+ callback=invalid_converter_callback,
141
+ ))
116
142
  """A test that a proper error is returned if an invalid converter is requested"""
117
143
 
118
- quality_note_callback = CheckLogContentsSuccess(["WARNING",
119
- const.QUAL_NOTE_OUT_MISSING.format(const.QUAL_2D_LABEL),
120
- const.QUAL_NOTE_OUT_MISSING.format(const.QUAL_3D_LABEL),
121
- const.QUAL_NOTE_IN_MISSING.format(const.QUAL_CONN_LABEL)])
122
- quality_note_test = ConversionTestSpec(filename="quartz.xyz",
123
- to_format="inchi",
124
- callback=quality_note_callback)
144
+ quartz_quality_note_callback = CheckLogContentsSuccess(["WARNING",
145
+ const.QUAL_NOTE_OUT_MISSING.format(const.QUAL_2D_LABEL),
146
+ const.QUAL_NOTE_OUT_MISSING.format(const.QUAL_3D_LABEL),
147
+ const.QUAL_NOTE_IN_MISSING.format(const.QUAL_CONN_LABEL)])
148
+ ethanol_quality_note_callback = CheckLogContentsSuccess(["WARNING",
149
+ "Potential data loss or extrapolation",
150
+ const.QUAL_NOTE_IN_MISSING.format(const.QUAL_CONN_LABEL)])
151
+ hemoglobin_quality_note_callback = CheckLogContentsSuccess(["WARNING",
152
+ "Potential data loss or extrapolation",
153
+ const.QUAL_NOTE_OUT_MISSING.format(const.QUAL_CONN_LABEL)])
154
+ l_all_test_specs.append(Spec(name="Quality note",
155
+ filename=["quartz.xyz", "ethanol.xyz", "hemoglobin.pdb"],
156
+ to_format=["inchi", "cml", "xyz"],
157
+ callback=[quartz_quality_note_callback,
158
+ ethanol_quality_note_callback,
159
+ hemoglobin_quality_note_callback],
160
+ ))
125
161
  """A test conversion which we expect to produce a warning for conversion quality issues, where the connections property
126
162
  isn't present in the input and has to be extrapolated, and the 2D and 3D coordinates properties aren't present in the
127
163
  output and will be lost"""
128
164
 
129
- cleanup_input_test = ConversionTestSpec(conversion_kwargs={"delete_input": True},
130
- callback=CheckFileStatus(expect_input_exists=False))
165
+ l_all_test_specs.append(Spec(name="Cleanup input",
166
+ conversion_kwargs={"delete_input": True},
167
+ callback=CheckFileStatus(expect_input_exists=False),
168
+ ))
131
169
  """A test that the input file to a conversion is deleted when cleanup is requested"""
132
170
 
133
- cant_read_xyz_callback = MultiCallback(CheckFileStatus(expect_output_exists=False,
134
- expect_log_exists=None),
135
- CheckException(ex_type=FileConverterAbortException,
136
- ex_message="Problems reading an XYZ file"))
137
- invalid_conversion_callback = MultiCallback(CheckFileStatus(expect_output_exists=False,
138
- expect_log_exists=None),
139
- CheckException(ex_type=FileConverterHelpException,
140
- ex_message="is not supported"))
141
- wrong_type_callback = MultiCallback(CheckFileStatus(expect_output_exists=False,
142
- expect_log_exists=None),
143
- CheckException(ex_type=FileConverterAbortException,
144
- ex_message="not a valid {} file"))
145
- failed_conversion_test = ConversionTestSpec(filename=["quartz_err.xyz", "hemoglobin.pdb", "1NE6.mmcif"],
146
- to_format=["inchi", "pdb", "cif"],
147
- conversion_kwargs=[{}, {}, {"from_format": "pdb"}],
148
- expect_success=False,
149
- callback=[cant_read_xyz_callback, invalid_conversion_callback,
150
- wrong_type_callback])
151
- """A test that a conversion which fails due to an invalid input file will properly fail"""
152
-
153
- max_size_callback = MultiCallback(CheckFileStatus(expect_output_exists=False),
154
- CheckLogContents("Output file exceeds maximum size"),
155
- CheckException(ex_type=FileConverterSizeException,
156
- ex_message="exceeds maximum size",
157
- ex_status_code=const.STATUS_CODE_SIZE))
158
- max_size_test = ConversionTestSpec(filename=["1NE6.mmcif", "caffeine-smi.tar.gz"],
159
- to_format="pdb",
160
- conversion_kwargs=[{"max_file_size": 0.0001}, {"max_file_size": 0.0005}],
161
- expect_success=False,
162
- callback=max_size_callback)
171
+ l_all_test_specs.append(Spec(name="Failed conversion - bad input file",
172
+ filename=["quartz_err.xyz", "cyclopropane_err.mol"],
173
+ to_format=["inchi", "xyz"],
174
+ expect_success=False,
175
+ converter_name=[CONVERTER_OB, CONVERTER_C2X],
176
+ callback=[MCB(CheckFileStatus(expect_output_exists=False,
177
+ expect_log_exists=None),
178
+ CheckException(ex_type=FileConverterAbortException,
179
+ ex_message="Problems reading an XYZ file")),
180
+ MCB(CheckFileStatus(expect_output_exists=False,
181
+ expect_log_exists=None),
182
+ CheckException(ex_type=FileConverterAbortException,
183
+ ex_message="Aborting: mol file contains no atoms"))],
184
+ ))
185
+ """A test that a conversion that fails due to an unreadable input file will properly fail"""
186
+
187
+ quartz_error_ob_callback = CheckLogContents(["ERROR",
188
+ "Problems reading an XYZ file: Could not read line #11, file error"])
189
+ l_all_test_specs.append(Spec(name="Errors in logs",
190
+ filename="quartz_err.xyz",
191
+ to_format="inchi",
192
+ converter_name=CONVERTER_OB,
193
+ expect_success=False,
194
+ callback=quartz_error_ob_callback,
195
+ ))
196
+ """A test that when a conversion fails, logs are still produced and contain the expected error message"""
197
+
198
+ l_all_test_specs.append(Spec(name="Failed conversion - invalid conversion",
199
+ filename=["Fapatite.ins", "nacl.mol"],
200
+ to_format=["cml", "xyz"],
201
+ expect_success=False,
202
+ converter_name=[CONVERTER_OB, CONVERTER_ATO],
203
+ callback=MCB(CheckFileStatus(expect_output_exists=False,
204
+ expect_log_exists=None),
205
+ CheckException(ex_type=FileConverterHelpException,
206
+ ex_message="is not supported")),
207
+ ))
208
+ """A test that a conversion that fails due an unsupported conversion will properly fail"""
209
+
210
+ l_all_test_specs.append(Spec(name="Failed Conversion - wrong input type",
211
+ filename="1NE6.mmcif",
212
+ to_format="cif",
213
+ conversion_kwargs={"from_format": "pdb"},
214
+ expect_success=False,
215
+ callback=MCB(CheckFileStatus(expect_output_exists=False,
216
+ expect_log_exists=None),
217
+ CheckException(ex_type=FileConverterAbortException,
218
+ ex_message="not a valid {} file")),
219
+ ))
220
+ """A test that a conversion which fails due to the wrong input file type will properly fail"""
221
+
222
+ l_all_test_specs.append(Spec(name="Large files",
223
+ filename=["ch3cl-esp.cub", "benzyne.molden", "periodic_dmol3.outmol",
224
+ "fullRhinovirus.pdb"],
225
+ to_format=["cdjson", "dmol", "mol", "cif"],
226
+ converter_name=[CONVERTER_OB, CONVERTER_OB, CONVERTER_OB, CONVERTER_C2X],
227
+ callback=CheckFileStatus(),
228
+ ))
229
+
230
+ max_size_callback = MCB(CheckFileStatus(expect_output_exists=False),
231
+ CheckLogContents("file exceeds maximum size"),
232
+ CheckException(ex_type=FileConverterSizeException,
233
+ ex_message="exceeds maximum size",
234
+ ex_status_code=const.STATUS_CODE_SIZE))
235
+ l_all_test_specs.append(Spec(name="Max size exceeded",
236
+ filename=["1NE6.mmcif", "caffeine-smi.tar.gz"],
237
+ to_format="pdb",
238
+ conversion_kwargs=[{"max_file_size": 0.0001}, {"max_file_size": 0.0005}],
239
+ expect_success=False,
240
+ callback=max_size_callback,
241
+ compatible_with_cla=False,
242
+ ))
163
243
  """A set of test conversion that the maximum size constraint is properly applied. In the first test, the input file
164
244
  will be greater than the maximum size, and the test should fail as soon as it checks it. In the second test, the input
165
245
  archive is smaller than the maximum size, but the unpacked files in it are greater, so it should fail midway through.
166
246
 
167
- NOTE: Not compatible with CLA tests, since the CLA doesn't allow the imposition of a maximum size.
247
+ Not compatible with CLA tests, since the CLA doesn't allow the imposition of a maximum size.
168
248
  """
169
249
 
170
250
 
171
- format_args_test = ConversionTestSpec(filename="caffeine.inchi",
172
- to_format="smi",
173
- conversion_kwargs=[{},
174
- {"data": {"from_flags": "a"}},
175
- {"data": {"from_flags": "a", "to_flags": "x"}},
176
- {"data": {"from_flags": "a", "to_flags": "kx"}},
177
- {"data": {"from_flags": "a", "to_flags": "kx",
178
- "to_options": "f4"}},
179
- {"data": {"from_flags": "a", "to_flags": "kx",
180
- "to_options": "f4 l5"}}
181
- ],
182
- callback=[MatchOutputFile("caffeine-no-flags.smi"),
183
- MatchOutputFile("caffeine-ia.smi"),
184
- MatchOutputFile("caffeine-ia-ox.smi"),
185
- MatchOutputFile("caffeine-ia-okx.smi"),
186
- MatchOutputFile("caffeine-ia-okx-oof4.smi"),
187
- MatchOutputFile("caffeine-ia-okx-oof4l5.smi")
188
- ]
189
- )
251
+ l_all_test_specs.append(Spec(name="Format args",
252
+ filename="caffeine.inchi",
253
+ to_format="smi",
254
+ conversion_kwargs=[{},
255
+ {"data": {"from_flags": "a"}},
256
+ {"data": {"from_flags": "a", "to_flags": "x"}},
257
+ {"data": {"from_flags": "a", "to_flags": "kx"}},
258
+ {"data": {"from_flags": "a", "to_flags": "kx",
259
+ "to_options": "f4"}},
260
+ {"data": {"from_flags": "a", "to_flags": "kx",
261
+ "to_options": "f4 l5"}}
262
+ ],
263
+ callback=[MatchOutputFile("caffeine.smi"),
264
+ MatchOutputFile("caffeine_a_in.smi"),
265
+ MatchOutputFile("caffeine_a_in_x_out.smi"),
266
+ MatchOutputFile("caffeine_a_in_kx_out.smi"),
267
+ MatchOutputFile("caffeine_a_in_kx_f4_out.smi"),
268
+ MatchOutputFile("caffeine_a_in_kx_f4_l5_out.smi")
269
+ ]
270
+ ))
190
271
  """A set of tests which checks that format args (for how to read from and write to specific file formats) are processed
191
272
  correctly, by matching tests using them to expected output files"""
192
273
 
193
274
 
194
- coord_gen_test = ConversionTestSpec(filename="caffeine.inchi",
195
- to_format="xyz",
196
- conversion_kwargs=[{},
197
- {"data": {COORD_GEN_KEY: "Gen2D",
198
- COORD_GEN_QUAL_KEY: "fastest"}},
199
- {"data": {COORD_GEN_KEY: "Gen3D",
200
- COORD_GEN_QUAL_KEY: "best"}}
201
- ],
202
- callback=[MatchOutputFile("caffeine.xyz"),
203
- MatchOutputFile("caffeine-2D-fastest.xyz"),
204
- MatchOutputFile("caffeine-3D-best.xyz"),
205
- ]
206
- )
275
+ l_all_test_specs.append(Spec(name="Coord gen",
276
+ filename="caffeine.inchi",
277
+ to_format="xyz",
278
+ conversion_kwargs=[{},
279
+ {"data": {COORD_GEN_KEY: "Gen2D",
280
+ COORD_GEN_QUAL_KEY: "fastest"}},
281
+ {"data": {COORD_GEN_KEY: "Gen3D",
282
+ COORD_GEN_QUAL_KEY: "best"}}
283
+ ],
284
+ callback=[MatchOutputFile("caffeine.xyz"),
285
+ MatchOutputFile("caffeine-2D-fastest.xyz"),
286
+ MatchOutputFile("caffeine-3D-best.xyz"),
287
+ ]
288
+ ))
207
289
  """A set of tests which checks that coordinate generation options are processed correctly, by matching tests using them
208
290
  to expected output files"""
291
+
292
+ l_library_test_specs = [x for x in l_all_test_specs if x.compatible_with_library]
293
+ """All test specs which are compatible with being run on the Python library"""
294
+
295
+ l_cla_test_specs = [x for x in l_all_test_specs if x.compatible_with_cla]
296
+ """All test specs which are compatible with being run on the command-line application"""
297
+
298
+ l_gui_test_specs = [x for x in l_all_test_specs if x.compatible_with_gui]
299
+ """All test specs which are compatible with being run on the GUI"""
@@ -102,13 +102,16 @@ class ConversionTestSpec:
102
102
  (as if using zip on the multiple lists) to test each element in turn.
103
103
  """
104
104
 
105
+ name: str
106
+ """The name of this test specification"""
107
+
105
108
  filename: str | Iterable[str] = "nacl.cif"
106
109
  """The name of the input file, relative to the input test data location, or a list thereof"""
107
110
 
108
111
  to_format: str | Iterable[str] = "pdb"
109
112
  """The format to test converting the input file to, or a list thereof"""
110
113
 
111
- name: str | Iterable[str] = CONVERTER_DEFAULT
114
+ converter_name: str | Iterable[str] = CONVERTER_DEFAULT
112
115
  """The name of the converter to be used for the test, or a list thereof"""
113
116
 
114
117
  conversion_kwargs: dict[str, Any] | Iterable[dict[str, Any]] = field(default_factory=dict)
@@ -124,6 +127,15 @@ class ConversionTestSpec:
124
127
  should take as its only argument a `ConversionTestInfo` and return a string. The string should be empty if the check
125
128
  is passed and should explain the failure otherwise."""
126
129
 
130
+ compatible_with_library: bool = True
131
+ """Whether or not this test spec is compatible with being run through the Python library, default True"""
132
+
133
+ compatible_with_cla: bool = True
134
+ """Whether or not this test spec is compatible with being run through the command-line application, default True"""
135
+
136
+ compatible_with_gui: bool = True
137
+ """Whether or not this test spec is compatible with being run through the GUI, default True"""
138
+
127
139
  def __post_init__(self):
128
140
  """Regularize the lengths of all attribute lists, in case some were provided as single values and others as
129
141
  lists, and set up initial values
@@ -131,7 +143,10 @@ class ConversionTestSpec:
131
143
 
132
144
  # To ease maintainability, we get the list of this class's attributes automatically from its __dict__, excluding
133
145
  # any which start with an underscore
134
- self._l_attr_names: list[str] = [attr_name for attr_name in self.__dict__ if not attr_name.startswith("_")]
146
+ self._l_attr_names: list[str] = [attr_name for attr_name in self.__dict__ if
147
+ not (attr_name.startswith("_") or
148
+ attr_name == "name" or
149
+ attr_name.startswith("compatible"))]
135
150
 
136
151
  l_single_val_attrs = []
137
152
  self._len: int = 1
@@ -196,7 +211,7 @@ class SingleConversionTestSpec:
196
211
  to_format: str
197
212
  """The format to test converting the input file to"""
198
213
 
199
- name: str | Iterable[str] = CONVERTER_DEFAULT
214
+ converter_name: str | Iterable[str] = CONVERTER_DEFAULT
200
215
  """The name of the converter to be used for the test"""
201
216
 
202
217
  conversion_kwargs: dict[str, Any] = field(default_factory=dict)
@@ -279,7 +294,7 @@ def _run_single_test_conversion_with_library(test_spec: SingleConversionTestSpec
279
294
  if test_spec.expect_success:
280
295
  run_converter(filename=qualified_in_filename,
281
296
  to_format=test_spec.to_format,
282
- name=test_spec.name,
297
+ name=test_spec.converter_name,
283
298
  upload_dir=input_dir,
284
299
  download_dir=output_dir,
285
300
  **test_spec.conversion_kwargs)
@@ -288,7 +303,7 @@ def _run_single_test_conversion_with_library(test_spec: SingleConversionTestSpec
288
303
  with pytest.raises(Exception) as exc_info:
289
304
  run_converter(filename=qualified_in_filename,
290
305
  to_format=test_spec.to_format,
291
- name=test_spec.name,
306
+ name=test_spec.converter_name,
292
307
  upload_dir=input_dir,
293
308
  download_dir=output_dir,
294
309
  **test_spec.conversion_kwargs)
@@ -359,7 +374,7 @@ def _run_single_test_conversion_with_cla(test_spec: SingleConversionTestSpec,
359
374
  if test_spec.expect_success:
360
375
  run_converter_through_cla(filename=qualified_in_filename,
361
376
  to_format=test_spec.to_format,
362
- name=test_spec.name,
377
+ name=test_spec.converter_name,
363
378
  input_dir=input_dir,
364
379
  output_dir=output_dir,
365
380
  log_file=os.path.join(output_dir, test_spec.log_filename),
@@ -369,7 +384,7 @@ def _run_single_test_conversion_with_cla(test_spec: SingleConversionTestSpec,
369
384
  with pytest.raises(SystemExit) as exc_info:
370
385
  run_converter_through_cla(filename=qualified_in_filename,
371
386
  to_format=test_spec.to_format,
372
- name=test_spec.name,
387
+ name=test_spec.converter_name,
373
388
  input_dir=input_dir,
374
389
  output_dir=output_dir,
375
390
  log_file=os.path.join(output_dir, test_spec.log_filename),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: psdi_data_conversion
3
- Version: 0.0.33
3
+ Version: 0.0.36
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/
@@ -403,13 +403,21 @@ In addition to the dependencies listed above, this project uses the assets made
403
403
 
404
404
  ### Installation
405
405
 
406
- The CLA and Python library are installed together. This package is not yet available on PyPI, and so must be installed locally. This can be done most easily with:
406
+ The CLA and Python library are installed together. This project is available on PyPI, and so can be installed via pip with:
407
+
408
+ ```bash
409
+ pip install psdi-data-conversion
410
+ ```
411
+
412
+ If you wish to install from source, this can be done most easily by cloning the project and then executing:
407
413
 
408
414
  ```bash
409
415
  pip install .
410
416
  ```
411
417
 
412
- executed from this project's directory. You can also replace the '.' in this command with the path to this project's directory to install it from elsewhere.
418
+ from this project's directory. You can also replace the '.' in this command with the path to this project's directory to install it from elsewhere.
419
+
420
+ **Note:** This project uses git to determine the version number. If you clone the repository, you won't have to do anything special here, but if you get the source e.g. by extracting a release archive, you'll have to do one additional step before running the command above. If you have git installed, simply run `git init` in the project directory and it will be able to install. Otherwise, edit the project's `pyproject.toml` file to uncomment the line that sets a fixed version, and comment out the lines that set it up to determine the version from git - these are pointed out in the comments there.
413
421
 
414
422
  Depending on your system, it may not be possible to install packages in this manner without creating a virtual environment to do so in. You can do this by first installing the `venv` module for Python3 with e.g.:
415
423
 
@@ -572,15 +580,23 @@ Enter https://data-conversion.psdi.ac.uk/ in a browser. Guidance on usage is giv
572
580
 
573
581
  ### Installation and Setup
574
582
 
575
- Install the package and its requirements, including the optional requirements used to run the GUI locally, by executing the following command from this project's directory:
583
+ This project is available on PyPI, and so can be installed via pip, including the necessary dependencies for the GUI, with:
584
+
585
+ ```bash
586
+ pip install psdi-data-conversion'[gui]'
587
+ ```
588
+
589
+ If you wish to install the project locally from source, this can be done most easily by cloning the project and then executing:
576
590
 
577
591
  ```bash
578
592
  pip install .'[gui]'
579
593
  ```
580
594
 
581
- If your system does not allow installs in this manner, it may be necessary to set up a virtual environment. See the instructions in the [command-line application installation](#installation) section above for how to do that, and then try to install again once you've set one up and activated it.
595
+ **Note:** This project uses git to determine the version number. If you clone the repository, you won't have to do anything special here, but if you get the source e.g. by extracting a release archive, you'll have to do one additional step before running the command above. If you have git installed, simply run `git init` in the project directory and it will be able to install. Otherwise, edit the project's `pyproject.toml` file to uncomment the line that sets a fixed version, and comment out the lines that set it up to determine the version from git - these are pointed out in the comments there.
582
596
 
583
- If you've cloned this repository, you can use the `run_local.sh` bash script to run the application. Otherwise (e.g. if you've installed from a wheel or PyPI), copy and paste the following into a script:
597
+ If your system does not allow installation in this manner, it may be necessary to set up a virtual environment. See the instructions in the [command-line application installation](#installation) section above for how to do that, and then try to install again once you've set one up and activated it.
598
+
599
+ If you've installed this repository from source, you can use the provided `run_local.sh` bash script to run the application. Otherwise (e.g. if you've installed from a wheel or PyPI), copy and paste the following into a script:
584
600
 
585
601
  ```bash
586
602
  #!/bin/bash
@@ -590,6 +606,13 @@ if [ -z $MAX_FILESIZE ]; then
590
606
  export MAX_FILESIZE=0
591
607
  fi
592
608
 
609
+ # The envvar MAX_FILESIZE_OB can be used to set the maximum allowed filesize in MB for the Open Babel converter - 0
610
+ # indicates no maximum. This is currently set to 1 MB by default as the converter seems to hang above this limit (not
611
+ # even allowing the process to be cancelled). This can be changed in the future if this is patched
612
+ if [ -z $MAX_FILESIZE_OB ]; then
613
+ export MAX_FILESIZE_OB=1
614
+ fi
615
+
593
616
  # Logging control - "full" sets server-style logging, which is necessary to produce the output logs with the expected
594
617
  # names. This should not be changed, or else errors will occur
595
618
  export LOG_MODE=full