AutoREACTER 0.2b1__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. autoreacter-0.2.3/AutoREACTER/__init__.py +316 -0
  2. autoreacter-0.2.3/AutoREACTER/_compat.py +60 -0
  3. autoreacter-0.2.3/AutoREACTER/arx_cli.py +497 -0
  4. autoreacter-0.2.3/AutoREACTER/cache.py +155 -0
  5. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/detector.py +259 -259
  6. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/functional_groups_detector.py +110 -83
  7. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/functional_groups_library.py +100 -17
  8. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/non_monomer_detector.py +20 -24
  9. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/reaction_detector.py +19 -12
  10. autoreacter-0.2.3/AutoREACTER/detectors/reactions_library.py +475 -0
  11. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/initialization.py +3 -6
  12. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/input_parser.py +107 -90
  13. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/FF_files/pcff.frc +5617 -0
  14. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/REACTER_files_builder.py +57 -29
  15. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/ff_locator.py +73 -0
  16. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/ff_validator.py +5 -4
  17. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/ff_wrapper.py +93 -0
  18. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/foyer_client/foyer_api_wrapper.py +336 -0
  19. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/foyer_client/foyer_lammps_support.py +192 -0
  20. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client/config.py +1 -0
  21. {autoreacter-0.2b1/AutoREACTER/reaction_preparation → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/lunar_client/locate_lunar.py +10 -4
  22. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client/lunar_api_wrapper.py +95 -0
  23. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client/lunar_executor.py +234 -0
  24. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client/lunar_utils.py +113 -0
  25. autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client/merge_builder.py +107 -0
  26. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/molecule_3d_preparation.py +21 -14
  27. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/reaction_processor/fragment_comparison.py +238 -238
  28. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/reaction_processor/prepare_reactions.py +37 -17
  29. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/reaction_processor/utils.py +161 -161
  30. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/reaction_processor/walker.py +206 -206
  31. autoreacter-0.2.3/AutoREACTER/session.py +157 -0
  32. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/simulation_setup.py +16 -17
  33. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/system_property_calculations.py +25 -24
  34. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/densification_writer.py +15 -15
  35. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/lammps_settings.py +1 -1
  36. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/post_eq_writer.py +9 -9
  37. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/pre_eq_writer.py +156 -156
  38. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/rxn_first_stage_writer.py +221 -221
  39. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/rxn_second_stage_writer.py +219 -219
  40. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/sim_setup/writers/writer.py +66 -66
  41. autoreacter-0.2.3/AutoREACTER.egg-info/SOURCES.txt +79 -0
  42. {autoreacter-0.2b1 → autoreacter-0.2.3}/LICENSE.md +20 -20
  43. autoreacter-0.2.3/MANIFEST.in +11 -0
  44. {autoreacter-0.2b1/AutoREACTER.egg-info → autoreacter-0.2.3}/PKG-INFO +25 -67
  45. autoreacter-0.2.3/README.md +74 -0
  46. autoreacter-0.2.3/docs/source/Draft.md +3 -0
  47. autoreacter-0.2.3/docs/source/_static/Overview.png +0 -0
  48. autoreacter-0.2.3/docs/source/_static/autoreacter_overview.png +0 -0
  49. autoreacter-0.2.3/docs/source/_static/logo.png +0 -0
  50. autoreacter-0.2.3/docs/source/api_reference.md +313 -0
  51. autoreacter-0.2.3/docs/source/change_log.md +124 -0
  52. {autoreacter-0.2b1 → autoreacter-0.2.3}/docs/source/conf.py +32 -3
  53. autoreacter-0.2.3/docs/source/contact.md +9 -0
  54. autoreacter-0.2.3/docs/source/getting-started.md +13 -0
  55. autoreacter-0.2.3/docs/source/getting_started_pip_installation.md +64 -0
  56. autoreacter-0.2.3/docs/source/getting_started_source_installation.md +138 -0
  57. autoreacter-0.2.3/docs/source/index.rst +31 -0
  58. autoreacter-0.2.3/docs/source/input-configuration.md +170 -0
  59. autoreacter-0.2.3/docs/source/overview.md +53 -0
  60. autoreacter-0.2.3/docs/source/supported-force-fields.md +14 -0
  61. autoreacter-0.2.3/docs/source/supported-reactions.md +110 -0
  62. autoreacter-0.2.3/examples/example_1.ipynb +253 -0
  63. autoreacter-0.2.3/examples/example_1.py +107 -0
  64. autoreacter-0.2.3/examples/example_1_inputs_count_mode.json +49 -0
  65. autoreacter-0.2.3/examples/example_1_inputs_count_mode_FF.json +40 -0
  66. autoreacter-0.2.3/examples/example_1_inputs_ratio_mode.json +41 -0
  67. autoreacter-0.2.3/examples/legacy/example_1.ipynb +427 -0
  68. autoreacter-0.2.3/examples/legacy/run_AutoREACTER.py +215 -0
  69. autoreacter-0.2.3/pyproject.toml +77 -0
  70. autoreacter-0.2.3/tests/test_lunar_api_wrapper.py +96 -0
  71. autoreacter-0.2b1/AutoREACTER/__init__.py +0 -46
  72. autoreacter-0.2b1/AutoREACTER/cache.py +0 -300
  73. autoreacter-0.2b1/AutoREACTER/detectors/reactions_library.py +0 -308
  74. autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client/config.py +0 -1
  75. autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client/lunar_api_wrapper.py +0 -694
  76. autoreacter-0.2b1/AutoREACTER/sim_setup/writers/__init__.py +0 -0
  77. autoreacter-0.2b1/AutoREACTER.egg-info/SOURCES.txt +0 -50
  78. autoreacter-0.2b1/AutoREACTER.egg-info/dependency_links.txt +0 -1
  79. autoreacter-0.2b1/AutoREACTER.egg-info/requires.txt +0 -6
  80. autoreacter-0.2b1/AutoREACTER.egg-info/top_level.txt +0 -6
  81. autoreacter-0.2b1/PKG-INFO +0 -139
  82. autoreacter-0.2b1/README.md +0 -122
  83. autoreacter-0.2b1/pyproject.toml +0 -25
  84. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/detectors/__init__.py +0 -0
  85. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/__init__.py +0 -0
  86. {autoreacter-0.2b1 → autoreacter-0.2.3}/AutoREACTER/reaction_preparation/build_reaction_system.py +0 -0
  87. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/__init__.py +0 -0
  88. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/reaction_processor → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/foyer_client}/__init__.py +0 -0
  89. {autoreacter-0.2b1/AutoREACTER/reaction_template_builder → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper/lunar_client}/__init__.py +0 -0
  90. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/modifiers_molecule_files.py +0 -0
  91. {autoreacter-0.2b1/AutoREACTER/reaction_preparation/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/ff_wrapper}/template_builder.py +0 -0
  92. {autoreacter-0.2b1/AutoREACTER/reaction_template_builder/lunar_client → autoreacter-0.2.3/AutoREACTER/reaction_preparation/reaction_processor}/__init__.py +0 -0
  93. {autoreacter-0.2b1/AutoREACTER/reaction_template_builder/reaction_template_pipeline → autoreacter-0.2.3/AutoREACTER/sim_setup}/__init__.py +0 -0
  94. {autoreacter-0.2b1/AutoREACTER/sim_setup → autoreacter-0.2.3/AutoREACTER/sim_setup/writers}/__init__.py +0 -0
  95. {autoreacter-0.2b1 → autoreacter-0.2.3}/setup.cfg +0 -0
@@ -0,0 +1,316 @@
1
+ """
2
+ AutoREACTER
3
+
4
+ AutoREACTER is a tool for automated reaction-based molecular system generation.
5
+ """
6
+ __version__ = "0.2.3"
7
+
8
+ __title__ = "AutoREACTER"
9
+ __author__ = "Janitha Mahanthe, Jacob Gissinger"
10
+
11
+ __package__ = "AutoREACTER"
12
+ __release__ = __version__
13
+ __license__ = "MIT"
14
+
15
+ __authors__ = [
16
+ "Janitha Mahanthe",
17
+ "Jacob Gissinger",
18
+ ]
19
+
20
+ __author__ = ", ".join(__authors__)
21
+
22
+ # Import all public API symbols
23
+ from importlib.metadata import version, PackageNotFoundError
24
+ from pathlib import Path
25
+ from typing import Optional
26
+ from .session import Session
27
+
28
+
29
+
30
+
31
+ """
32
+ Public API for the AutoREACTER (ARX) pipeline.
33
+
34
+ This module exposes a **global-session** interface: call :func:`run` once to
35
+ bootstrap a workflow from an input file, then use the remaining functions to
36
+ inspect molecules, select reactions and non-reactants, and finally run the
37
+ full simulation pipeline. Each function delegates to the currently active
38
+ :class:`ARXCLI` instance behind the scenes.
39
+
40
+ Usage (e.g. in a Jupyter notebook)::
41
+
42
+ import AutoREACTER as arx
43
+
44
+ arx.run("input.json")
45
+ arx.show_molecules()
46
+ arx.show_functional_groups()
47
+ arx.show_reactions()
48
+ arx.select_reactions()
49
+ arx.show_non_reactants()
50
+ arx.select_non_reactants()
51
+ arx.process()
52
+
53
+ All public symbols are listed in :data:`__all__`.
54
+
55
+ :data:`__all__` includes:
56
+ - ``run``
57
+ - ``show_molecules``
58
+ - ``show_functional_groups``
59
+ - ``show_reactions``
60
+ - ``select_reactions``
61
+ - ``show_non_reactants``
62
+ - ``select_non_reactants``
63
+ - ``process``
64
+ """
65
+
66
+ from .arx_cli import ARXCLI
67
+ from PIL import Image
68
+
69
+ # ---------------------------------------------------------------------------
70
+ # Global session handle – holds the *single* active workflow instance.
71
+ # The `run()` function is the only way to create (or replace) it.
72
+ # ---------------------------------------------------------------------------
73
+ _active_workflow = None # type: ARXCLI | None
74
+
75
+
76
+ def _ensure_workflow() -> ARXCLI:
77
+ """
78
+ Return the active :class:`ARXCLI` instance, raising if none exists.
79
+
80
+ This is the single choke-point used by every public function before
81
+ delegating. It guarantees that the user called :func:`run` first.
82
+
83
+ Returns
84
+ -------
85
+ ARXCLI
86
+ The currently active workflow session.
87
+
88
+ Raises
89
+ ------
90
+ RuntimeError
91
+ If :func:`run` has not been called yet (i.e. no session is active).
92
+ """
93
+ if _active_workflow is None:
94
+ raise RuntimeError(
95
+ "No active session. Please run `arx.run('your_file.json')` first."
96
+ )
97
+ return _active_workflow
98
+
99
+
100
+ # ===================================================================
101
+ # UTILITY FUNCTIONS
102
+ # ===================================================================
103
+
104
+ def session() -> Session:
105
+ """
106
+ Get the active :class:`Session` object from the current workflow.
107
+ Returns
108
+ -------
109
+ Session
110
+ The active session object containing all workflow state and data.
111
+ """
112
+ return _ensure_workflow().session
113
+
114
+ # ===================================================================
115
+ # PUBLIC API
116
+ # ===================================================================
117
+
118
+ def run(input_file):
119
+ """
120
+ Create or replace the active AutoREACTER workflow session.
121
+
122
+ Parameters
123
+ ----------
124
+ input_file : str or pathlib.Path
125
+ Path to the AutoREACTER input JSON file.
126
+
127
+ Returns
128
+ -------
129
+ ARXCLI
130
+ Active AutoREACTER workflow object.
131
+ """
132
+ global _active_workflow
133
+
134
+ input_file = Path(input_file).expanduser().resolve()
135
+
136
+ if not input_file.exists():
137
+ raise FileNotFoundError(f"Input file not found: {input_file}")
138
+
139
+ _active_workflow = ARXCLI(input_file)
140
+ return _active_workflow
141
+
142
+
143
+ def show_molecules() -> Image:
144
+ """
145
+ Display the 2D structures of all molecules in the current session.
146
+
147
+ This triggers molecule visualisation (RDKit images) and is safe to call
148
+ multiple times – the underlying detection runs only once.
149
+
150
+ Returns
151
+ -------
152
+ Image
153
+ Visualisation of all molecules, saved to the session's output directory.
154
+ """
155
+ return _ensure_workflow().show_molecules()
156
+
157
+
158
+ def show_functional_groups() -> Image:
159
+ """
160
+ Display the detected functional groups for each molecule.
161
+
162
+ Functional-group detection must have completed; if it hasn't, this method
163
+ triggers it automatically (idempotent). The visualisation highlights the
164
+ matched SMARTS patterns on each molecule.
165
+
166
+ Returns
167
+ -------
168
+ Image
169
+ Visualisation of functional groups, saved to the session's output directory.
170
+ """
171
+ return _ensure_workflow().show_functional_groups()
172
+
173
+
174
+ def show_reactions() -> Image:
175
+ """
176
+ Display the chemical reactions identified by the pipeline.
177
+
178
+ If reaction detection has not run yet, it is triggered first. The output
179
+ includes reaction templates and their mappings onto the input molecules.
180
+
181
+ Returns
182
+ -------
183
+ Image
184
+ Visualisation of reactions, saved to the session's output directory.
185
+ """
186
+ return _ensure_workflow().show_reactions()
187
+
188
+
189
+ def select_reactions() -> None:
190
+ """
191
+ Interactively select which reaction(s) to proceed with.
192
+
193
+ If multiple candidate reactions were identified, the user is prompted to
194
+ choose. When only one reaction is found it is auto-selected. This step
195
+ must complete before non-reactants can be selected or :func:`process` can
196
+ be called.
197
+
198
+ Returns
199
+ -------
200
+ None
201
+ Updates the internal :class:`ErrorHandler` state machine.
202
+ """
203
+ _ensure_workflow().select_reactions()
204
+
205
+
206
+ def show_non_reactants() -> Image:
207
+ """
208
+ Display the non-reactant species detected in the simulation box.
209
+
210
+ Non-reactant detection depends on reaction selection having already
211
+ occurred; if it hasn't, an error will be raised.
212
+
213
+ Returns
214
+ -------
215
+ Image
216
+ Visualisation of non-reactant species, saved to the session's output directory.
217
+ """
218
+ return _ensure_workflow().show_non_reactants()
219
+
220
+
221
+ def select_non_reactants() -> None:
222
+ """
223
+ Interactively select which non-reactant species to include.
224
+
225
+ This may prompt the user to pick from a list of detected species. Must
226
+ be called after :func:`select_reactions` and before :func:`process`.
227
+
228
+ Returns
229
+ -------
230
+ None
231
+ Updates the internal :class:`ErrorHandler` state machine.
232
+ """
233
+ _ensure_workflow().select_non_reactants()
234
+
235
+ def prepare_reactions() -> None:
236
+ """
237
+ Prepare the reaction templates for simulation.
238
+
239
+ This is an intermediate step that performs reaction-template preparation
240
+ without running the full pipeline. It is not intended for end-users but
241
+ may be useful for debugging or development.
242
+
243
+ Returns
244
+ -------
245
+ None
246
+ Writes prepared reaction templates to the session's output directory.
247
+ Updates the internal :class:`ErrorHandler` state machine.
248
+ """
249
+ _ensure_workflow().prepare_reactions()
250
+
251
+
252
+ def show_reaction_templates(highlight_type: Optional[str] = "template") -> Image:
253
+ """
254
+ Visualise the prepared reaction templates.
255
+
256
+ This is an intermediate step that visualises the reaction templates after
257
+ preparation. It is not intended for end-users but may be useful for
258
+ debugging or development.
259
+
260
+ Returns
261
+ -------
262
+ Image
263
+ Visualisation of prepared reaction templates, saved to the session's output directory.
264
+ """
265
+ highlight_type = highlight_type.lower() if highlight_type else "template"
266
+ highlight_types = [
267
+ "template", # Highlight the reaction template itself (i.e. the changed bonds).
268
+ "edge", # Highlight the edge atoms (dihedral distance away from the reaction center).
269
+ "initiators", # Highlight the initiator atoms/bonds that trigger the reaction.
270
+ "delete" # Highlight the atoms/bonds that are deleted in the reaction.
271
+ ]
272
+ if highlight_type not in highlight_types:
273
+ raise ValueError(f"Invalid highlight_type: {highlight_type}. Must be one of {highlight_types}.")
274
+ return _ensure_workflow().show_reaction_templates(highlight_type=highlight_type)
275
+
276
+
277
+ def process() -> None:
278
+ """
279
+ Execute the full simulation setup pipeline.
280
+
281
+ This is the final step. It performs, in order:
282
+
283
+ 1. 3D geometry generation
284
+ 2. Force-field assignment (via :class:`FFWrapper`)
285
+ 3. REACTER file creation
286
+ 4. LAMMPS input generation
287
+
288
+ All preceding steps (reaction selection, non-reactant selection) must have
289
+ completed first; otherwise a :class:`RuntimeError` is raised.
290
+
291
+ Returns
292
+ -------
293
+ None
294
+ Writes all simulation artifacts to the session's output directory.
295
+ """
296
+ _ensure_workflow().process()
297
+
298
+
299
+ # Expose only these commands to the user
300
+ __all__ = [
301
+ "__title__",
302
+ "__version__",
303
+ "__release__",
304
+ "__authors__",
305
+ "__license__",
306
+ "run",
307
+ "show_molecules",
308
+ "show_functional_groups",
309
+ "show_reactions",
310
+ "select_reactions",
311
+ "show_non_reactants",
312
+ "select_non_reactants",
313
+ "prepare_reactions",
314
+ "show_reaction_templates",
315
+ "process",
316
+ ]
@@ -0,0 +1,60 @@
1
+ import sys
2
+ import collections
3
+ import collections.abc
4
+ import numpy as np
5
+
6
+ def apply_legacy_patches():
7
+ """
8
+ Injects removed aliases back into numpy and collections at runtime,
9
+ and bridges the OpenMM simtk namespace for older versions of Foyer/mBuild.
10
+ """
11
+ # 1. Restore removed Collections aliases
12
+ _missing_classes = [
13
+ "MutableSet", "MutableMapping", "Mapping", "MutableSequence",
14
+ "Sequence", "Set", "Iterable", "Iterator", "Callable",
15
+ "Container", "Hashable", "ItemsView", "KeysView", "ValuesView"
16
+ ]
17
+ for _name in _missing_classes:
18
+ if not hasattr(collections, _name) and hasattr(collections.abc, _name):
19
+ setattr(collections, _name, getattr(collections.abc, _name))
20
+
21
+ # 2. Restore removed NumPy aliases
22
+ if not hasattr(np, "float"): np.float = float
23
+ if not hasattr(np, "int"): np.int = int
24
+ if not hasattr(np, "complex"): np.complex = complex
25
+ if not hasattr(np, "bool"): np.bool = np.bool_
26
+ if not hasattr(np, "object"): np.object = np.object_
27
+ if not hasattr(np, "str"): np.str = np.str_
28
+
29
+ # 3. Robust OpenMM 'simtk' shim for Python 3.12+
30
+ try:
31
+ import sys
32
+ import types
33
+ import openmm
34
+ import openmm.app
35
+ import openmm.app.element
36
+ import openmm.unit
37
+
38
+ # Create pure, fake modules to bypass strict filesystem import checks
39
+ simtk = types.ModuleType("simtk")
40
+ simtk_openmm = types.ModuleType("simtk.openmm")
41
+ simtk_openmm_app = types.ModuleType("simtk.openmm.app")
42
+
43
+ # Copy the contents of the real modules into our fake ones
44
+ simtk_openmm.__dict__.update(openmm.__dict__)
45
+ simtk_openmm_app.__dict__.update(openmm.app.__dict__)
46
+
47
+ # Manually wire the internal tree together
48
+ simtk.openmm = simtk_openmm
49
+ simtk.unit = openmm.unit
50
+ simtk_openmm.app = simtk_openmm_app
51
+ simtk_openmm_app.element = openmm.app.element
52
+
53
+ # Register them in sys.modules so the 'import' statements find them instantly
54
+ sys.modules["simtk"] = simtk
55
+ sys.modules["simtk.openmm"] = simtk_openmm
56
+ sys.modules["simtk.openmm.app"] = simtk_openmm_app
57
+ sys.modules["simtk.openmm.app.element"] = openmm.app.element
58
+ sys.modules["simtk.unit"] = openmm.unit
59
+ except ImportError:
60
+ pass