Source code for schrodinger.application.matsci.smartsutilsgui
"""
GUI elements for working with SMARTS patterns
Copyright Schrodinger, LLC. All rights reserved.
"""
import warnings
from schrodinger.application.matsci import atomicsymbolsgui as symbolsgui
from schrodinger.application.matsci import rdpattern
from schrodinger.infra import mm
from schrodinger.structutils import analyze
[docs]class SMARTSNameValidator(symbolsgui.AtomNameLabelValidator):
"""
Ensures that the line edit contains only valid SMARTS name characters
"""
VALID_LABEL_PUNCTUATION = '_-()[]'
[docs]def populate_smarts_edit(smarts_edit,
maestro,
warning,
append=False,
delim=' ',
canvas_api=False,
use_rdkit=False,
fall_back=False,
check_connectivity=True,
allow_intermolecular=False):
"""
Populates the smarts edit with smarts pattern grabbed from WS. If append
is true then the smarts pattern is appended to smarts_edit with delim
(space as default) as delimiter else smarts_edit is replaced with the
given smarts pattern.
:param swidgets.SMARTSEdit smarts_edit: The smarts edit on which population
of smarts pattern is to be done
:param schrodinger.maestro.maestro maestro: maestro provides structure
and selected atom index
:param function warning: prints warning message
:param bool append: If flag is true then smarts is appended to smarts_edit
with delim as delimiter else smarts_edit is replaced with smarts
:param str delim: The delimiter used when append is true.
:param bool canvas_api: whether to use analyze.generate_smarts or
analyze.generate_smarts_canvas
:param bool use_rdkit: Whether to use rdkit
:param bool fall_back: whether to fall back on using analyze.generate_smarts
if canvas/rdkit fails, used only if canvas_api is
True
:param bool check_connectivity: If True, check for whether the atoms given
are connected and raise a ValueError if they are not. SMARTS generation
will give bogus results for unconnected atoms.
:param bool allow_intermolecular: If check_connectivity is False this controls whether
matches must be intramolecular or allowed to be intermolecular
"""
smarts = get_smarts_from_ws(maestro,
warning,
canvas_api=canvas_api,
use_rdkit=use_rdkit,
fall_back=fall_back,
check_connectivity=check_connectivity,
allow_intermolecular=allow_intermolecular)
if not smarts:
return
if append:
patterns = smarts_edit.getSMARTSPatterns()
patterns.append(smarts)
smarts_edit.setText(delim.join(patterns))
else:
smarts_edit.setText(smarts)
[docs]def get_smarts_from_ws(maestro,
warning,
canvas_api=False,
use_rdkit=False,
fall_back=False,
check_connectivity=True,
allow_intermolecular=False):
"""
Get the SMARTS pattern for the selected atoms in the workspace and
insert it into the SMARTS entry
:type maestro: `schrodinger.maestro.maestro`
:param maestro: maestro provides structure and selected atom index
:type warning: function
:param warning: prints warning message
:type canvas_api: bool
:param canvas_api: whether to use analyze.generate_smarts or
analyze.generate_smarts_canvas
:type canvas_api: bool
:param bool use_rdkit: Whether to use rdkit
:type fall_back: bool
:param fall_back: whether to fall back on using analyze.generate_smarts
if canvas/rdkit fails, used only if canvas_api is
True
:type check_connectivity: bool
:param check_connectivity:
If True, check for whether the atoms given are connected and raise a
ValueError if they are not. SMARTS generation will give bogus
results for unconnected atoms.
:type allow_intermolecular: bool
:param allow_intermolecular: if check_connectivity is False this controls whether
matches must be intramolecular or allowed to be intermolecular
:rtype: str or None
:return: smarts pattern selected from workspace or None if any of the
validation fails
"""
assert not (canvas_api and use_rdkit), ('Canvas and rdkit cannot be both '
'requested.')
selection = maestro.selected_atoms_get()
if not selection:
warning('No workspace atoms selected')
return None
try:
struct = maestro.get_included_entry()
except RuntimeError:
warning("There has to be at least one and "
"only one included entry in the Workspace.")
return None
if not check_connectivity and not allow_intermolecular:
if len(set(struct.atom[i].molecule_number for i in selection)) > 1:
warning('Selection includes atoms from different molecules.')
return None
use_default = not (canvas_api or use_rdkit)
if canvas_api:
try:
smarts = analyze.generate_smarts_canvas(
struct,
atom_subset=selection,
check_connectivity=check_connectivity)
except (RuntimeError, ValueError) as msg:
if not fall_back:
warning(str(msg))
return None
else:
use_default = True
elif use_rdkit:
try:
# generate_smarts as well as generate_smarts_canvas with defaults
# don't return chiral smarts, thus set it to false here. Also note
# that converting to rdkit including stereo can be very slow (RB 67298)
include_stereo = False
smarts = rdpattern.to_smarts(struct,
include_stereo=include_stereo,
atom_subset=selection,
check_connectivity=check_connectivity)
except ValueError as msg:
if not fall_back:
warning(str(msg))
return None
else:
use_default = True
if use_default:
try:
# Changed default of generate_smarts_canvas to generate_smarts
# due to CANVAS-5621
with warnings.catch_warnings():
warnings.filterwarnings("ignore",
category=DeprecationWarning,
message="analyze.generate_smarts")
smarts = analyze.generate_smarts(
struct,
atom_subset=selection,
check_connectivity=check_connectivity)
except ValueError as msg:
warning(str(msg))
return None
except mm.MmException:
# Something went very wrong with obtaining the SMARTS pattern, but
# we don't know what and the Exception message is not user
# appropriate
warning('Unable to obtain a SMARTS pattern for the selected atoms')
return None
return smarts