Beispiel #1
0
def open_mol2(session, path, file_name, auto_style, atomic):
    from chimerax.io import open_input
    with open_input(path, encoding='utf-8') as stream:
        p = Mol2Parser(session, stream, file_name, auto_style, atomic)
    structures = p.structures
    status = "Opened %s containing %d structures (%d atoms, %d bonds)" % (
        file_name, len(structures), sum([s.num_atoms for s in structures]),
        sum([s.num_bonds for s in structures]))
    return structures, status
Beispiel #2
0
def open_pdbqt(session, path, file_name, auto_style, atomic):
    structures, _status = session.open_command.open_data(path,
                                                         format="pdb",
                                                         log_errors=False)
    from chimerax.io import open_input
    with open_input(path, encoding='utf-8') as f:
        _extract_metadata(session, f, structures)
    status = "Opened %s containing %d structures (%d atoms, %d bonds)" % (
        file_name, len(structures), sum([s.num_atoms for s in structures]),
        sum([s.num_bonds for s in structures]))
    return structures, status
Beispiel #3
0
def _cactus_fetch(session, smiles, web_smiles):
    cactus_site = "cactus.nci.nih.gov"
    from chimerax.io import open_input
    from urllib.error import URLError
    try:
        reply = open_input(
            "http://%s/cgi-bin/translate.tcl?smiles=%s&format=sdf&astyle=kekule"
            "&dim=3D&file=" % (cactus_site, web_smiles),
            session.data_formats['sdf'].encoding)
    except URLError as e:
        pass
    else:
        for line in reply:
            if "Click here" in line and line.count(
                    '"') == 2 and "href=" in line:
                pre, url, post = line.split('"')
                return "http://%s%s" % (cactus_site, url)
    raise SmilesTranslationError("Cactus could not translate %s" % smiles)
Beispiel #4
0
def fetch_smiles(session, smiles_string, **kw):

    printables = []
    for char in smiles_string:
        if char.isprintable() and not char.isspace():
            printables.append(char)
    diff = len(smiles_string) - len(printables)
    if diff > 0:
        session.logger.warning(
            "Removed %d blank/non-printable characters from SMILES string" %
            diff)
        smiles_string = "".join(printables)
    # triple-bond characters (#) and the '/' stereo-chemistry indicator get mangled by the
    # http protocol, so switch to http-friendly equivalent
    web_smiles = smiles_string.replace('#', "%23").replace('/', "%2F")
    for fetcher, moniker, ack_name, info_url in fetcher_info:
        try:
            path = fetcher(session, smiles_string, web_smiles)
        except SmilesTranslationError:
            pass
        else:
            from chimerax.sdf import read_sdf
            from chimerax import io
            structures, status = read_sdf(
                session, io.open_input(path, encoding='utf=8'), path)
            if structures:
                for s in structures:
                    s.name = "smiles:" + smiles_string
                break
        session.logger.info(
            "Failed to translate SMILES to 3D structure via %s web service"
            "(SMILES: %s)" % (moniker, smiles_string))
    else:
        raise SmilesTranslationError(
            "Web services failed to translate SMILES string to 3D structure.")
    translation_info = "Translated SMILES to 3D structure via %s web service (SMILES: %s)" % (
        moniker, smiles_string)
    return structures, translation_info
Beispiel #5
0
def open_file(session,
              stream,
              fname,
              format_name="FASTA",
              return_vals=None,
              alignment=True,
              ident=None,
              auto_associate=True,
              **kw):
    ns = {}
    try:
        exec("from .io.read%s import read" % format_name.replace(' ', '_'),
             globals(), ns)
    except ImportError:
        raise ValueError("No file parser installed for %s files" % format_name)
    if stream is None:
        import os.path
        path = fname
        fname = os.path.basename(path)
        from chimerax import io
        stream = io.open_input(path, 'utf-8')
    try:
        seqs, file_attrs, file_markups = ns['read'](session, stream)
    except FormatSyntaxError as err:
        raise IOError("Syntax error in %s file '%s': %s" %
                      (format_name, fname, err))
    if not seqs:
        raise ValueError("No sequences found in %s file '%s'!" %
                         (format_name, fname))
    uniform_length = True
    for s in seqs:
        if uniform_length and len(s) != len(seqs[0]):
            uniform_length = False
            differing_seq = s
        if s.name.endswith(" x 2") or (
                '/' in s.name
                and s.name[:s.name.rindex('/')].endswith(" x 2")):
            # set up circular attribute
            nogaps = s.ungapped()
            if nogaps[:len(nogaps) / 2] == nogaps[len(nogaps) / 2:]:
                s.circular = True
    if return_vals == "seqs":
        return seqs
    from chimerax.core.errors import UserError
    if alignment:
        if not uniform_length:
            raise UserError(
                "Sequence '%s' differs in length from preceding sequences, and"
                " it is therefore impossible to open these sequences as an alignment.  If"
                " you want to open the sequences individually, specify 'false' as the value"
                " of the 'alignment' keyword in the 'open' command." %
                differing_seq.name)
        alignments = [
            session.alignments.new_alignment(
                seqs,
                ident if ident is not None else fname,
                attrs=file_attrs,
                markups=file_markups,
                auto_associate=auto_associate,
                **kw)
        ]
    else:
        if ident is None:
            ident = fname
        alignments = []
        for i, seq in enumerate(seqs):
            final_ident = ident if len(seqs) == 1 else "%s-%d" % (ident, i + 1)
            alignments.append(
                session.alignments.new_alignment([seq],
                                                 final_ident,
                                                 auto_associate=auto_associate,
                                                 **kw))
    if return_vals == "alignments":
        return alignments
    return [], "Opened %d sequences from %s" % (len(seqs), fname)
Beispiel #6
0
def defattr(session, file_name, *, log=False, restriction=None):
    """define attributes on objects

    Parameters
    ----------
    file_name : string
      Input file in 'defattr' format
    log : bool
      Whether to log assignment info
    restriction : Structures Collection or None
      If not None, structures to restrict the assignments to
      (in addition to any restrictions in the defattr file)
    """

    if restriction is None:
        from chimerax.atomic import all_structures
        restriction = all_structures(session)

    control_defaults = {
        'match mode': "any",
        'recipient': "atoms",
        'none handling': "None"
    }
    from chimerax.atomic import Atom, Bond, Pseudobond, Residue, Chain, Structure
    recipient_info = {
        "atoms": (Atom, lambda objs: objs.atoms),
        "bonds": (Bond, lambda objs: objs.bonds),
        "pseudobonds": (Pseudobond, lambda objs: objs.pseudobonds),
        "residues": (Residue, lambda objs: objs.residues),
        "chains": (Chain, lambda objs: objs.chains),
        # since we always restrict to structures, can just use Objects.models()
        "molecules": (Structure, lambda objs: objs.models),
        "structures": (Structure, lambda objs: objs.models),
    }
    legal_control_values = {
        'match mode': set(["any", "non-zero", "1-to-1"]),
        'recipient': set(recipient_info.keys()),
        'none handling': set(["None", "string", "delete"])
    }
    all_info = []

    def append_all_info(attr_info,
                        data_info,
                        line_num,
                        *,
                        ai=all_info,
                        fn=file_name):
        if 'attribute' not in attr_info:
            raise SyntaxError(
                "No attribute name defined for data lines %d and earlier in %s"
                % (line_num, fn))
        if not data_info:
            raise SyntaxError("No data lines for attribute '%s' in %s" %
                              (attr_info['attribute'], fn))
        ai.append((attr_info, data_info))

    from chimerax.core.commands import AtomSpecArg, AttrNameArg, AnnotationError, NoneArg, ColorArg, commas
    from chimerax.core.commands import IntArg, FloatArg
    from chimerax.io import open_input
    with open_input(file_name, encoding="utf-8") as f:
        data = []
        attrs = {}
        for lnum, raw_line in enumerate(f):
            # spaces in values could be significant, so instead of stripping just drop the '\n'
            # (which all line endings are translated to if newline=None [default] for open())
            line = raw_line[:-1]
            if not line.strip() or line[0] == '#':
                continue

            if line[0] == '\t':
                # data line
                datum = line[1:].split('\t')
                if len(datum) != 2:
                    raise SyntaxError(
                        "Data line %d in %s not of the form: <tab> atomspec <tab> value"
                        % (lnum + 1, file_name))
                data.append((lnum + 1, *datum))
                continue
            # control line
            try:
                name, value = line.split(": ")
            except ValueError:
                raise SyntaxError(
                    "Line %d in %s is either not of the form 'name: value'"
                    " or is missing initial tab" % (lnum + 1, file_name))
            name = name.strip().lower()
            value = value.strip()
            if name in attrs:
                # presumably another set of control/data lines starting
                append_all_info(attrs, data, lnum + 1)
                attrs = {}
                data = []
            if name == 'attribute':
                try:
                    final_value, *args = AttrNameArg.parse(value, session)
                except AnnotationError as e:
                    raise SyntaxError(
                        "Bad attribute name ('%s') given on line %d of %s: %s"
                        % (value, lnum + 1, file_name, str(e)))
            elif name not in legal_control_values:
                raise SyntaxError(
                    "Unrecognized control type ('%s') given on line %d of %s" %
                    (name, lnum + 1, file_name))
            elif value not in legal_control_values[name]:
                raise SyntaxError(
                    "Illegal control value ('%s') for %s given on line %d of %s; legal"
                    " values are: %s" % (value, name, lnum + 1, file_name,
                                         commas(legal_control_values[name])))
            else:
                final_value = value
            attrs[name] = final_value
        append_all_info(attrs, data, lnum + 1)

    for attr_info, data_info in all_info:
        attr_name = attr_info['attribute']
        color_attr = attr_name.lower().endswith(
            'color') or attr_name.lower().endswith('colour')

        match_mode = attr_info.get('match mode',
                                   control_defaults['match mode'])

        none_handling = attr_info.get('none handling',
                                      control_defaults['none handling'])
        none_okay = none_handling != 'string'
        none_seen = False
        eval_vals = ["true", "false"]
        if none_okay:
            eval_vals.append("none")

        recipient = attr_info.get('recipient', control_defaults['recipient'])
        recip_class, instance_fetch = recipient_info[recipient]
        seen_types = set()
        try:
            pre_existing_attr = getattr(recip_class, attr_name)
        except AttributeError:
            pass
        else:
            if callable(pre_existing_attr):
                raise ValueError(
                    "%s is a method of the %s class and cannot be redefined" %
                    (attr_name, recip_class.__name__))
            if attr_name[0].isupper():
                raise ValueError(
                    "%s is a constant in the %s class and cannot be redefined"
                    % (attr_name, recip_class.__name__))

        for line_num, spec, value_string in data_info:
            try:
                atom_spec, *args = AtomSpecArg.parse(spec, session)
            except AnnotationError as e:
                raise SyntaxError("Bad atom specifier (%s) on line %d of %s" %
                                  (spec, line_num, file_name))

            try:
                objects = atom_spec.evaluate(session, models=restriction)
            except Exception as e:
                raise SyntaxError(
                    "Error evaluating atom specifier (%s) on line %d of %s: %s"
                    % (spec, line_num, file_name, str(e)))

            matches = instance_fetch(objects)

            if not matches and match_mode != "any":
                raise SyntaxError(
                    "Selector (%s) on line %d of %s matched nothing" %
                    (spec, line_num, file_name))
            if len(matches) > 1 and match_mode == "1-to-1":
                raise SyntaxError(
                    "Selector (%s) on line %d of %s matched multiple %s" %
                    (spec, line_num, file_name, recipient))

            if log:
                session.logger.info(
                    "Selector %s matched %s" %
                    (spec, commas([str(x)
                                   for x in matches], conjunction="and")))

            if not value_string:
                raise SyntaxError("No data value on line %d of %s" %
                                  (line_num, file_name))

            # Can't just use normal argument parsers willy nilly since strings are allowed to have
            # leading/trailing whitespace, don't want to accept shorten ed forms of booleans, etc.
            if color_attr:
                try:
                    value, text, rest = ColorArg.parse(value_string, session)
                    if rest:
                        raise AnnotationError("trailing text")
                    seen_types.add("color")
                    value = value.uint8x4()
                except AnnotationError:
                    if none_okay:
                        try:
                            value, text, rest = NoneArg.parse(
                                value_string, session)
                            if rest:
                                raise AnnotationError("trailing text")
                            seen_types.add(None)
                        except AnnotationError:
                            raise SyntaxError(
                                "Value (%s) on line %d of %s is not recognizable as either a"
                                " color value or None" %
                                (value_string, line_num, file_name))
                    else:
                        raise SyntaxError(
                            "Value (%s) on line %d of %s is not recognizable as a color value"
                            % (value_string, line_num, file_name))
            else:
                if value_string.strip() != value_string:
                    value = value_string
                    seen_types.add(str)
                elif value_string.startswith('"') and value_string.endswith(
                        '"'):
                    value = value_string[1:-1]
                    seen_types.add(str)
                elif value_string.lower() in eval_vals:
                    value = eval(value_string.capitalize())
                    if value is None:
                        seen_types.add(None)
                    else:
                        seen_types.add(bool)
                else:
                    try:
                        value, text, rest = IntArg.parse(value_string, session)
                        if rest:
                            raise AnnotationError("trailing text")
                        seen_types.add(int)
                    except AnnotationError:
                        try:
                            value, text, rest = FloatArg.parse(
                                value_string, session)
                            if rest:
                                raise AnnotationError("trailing text")
                            seen_types.add(float)
                        except AnnotationError:
                            value = value_string
                            seen_types.add(str)

            for match in matches:
                if value is not None or none_handling == "None":
                    setattr(match, attr_name, value)
                elif hasattr(match, attr_name):
                    if pre_existing_attr:
                        raise RuntimeError(
                            "Cannot remove builtin attribute %s from class %s"
                            % (attr_name, recip_class.__name__))
                    else:
                        delattr(match, attr_name)

            can_return_none = None in seen_types
            seen_types.discard(None)
            if len(seen_types) == 1:
                seen_type = seen_types.pop()
                attr_type = None if seen_type == "color" else seen_type
            elif seen_types == set([int, float]):
                attr_type = float
            else:
                attr_type = None
            recip_class.register_attr(session,
                                      attr_name,
                                      "defattr command",
                                      attr_type=attr_type,
                                      can_return_none=can_return_none)
Beispiel #7
0
def _get_stream(mgr, file_name, encoding):
    path = _get_path(mgr, file_name, True, check_compression=False)
    from chimerax import io
    return io.open_input(path, encoding)