Repository navigation
RESID in ProForma #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RESID in ProForma #214
Changes from all commits
d043cf7
2b95a22
671605a
a8ac480
669719a
1427035
fa211ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,8 @@ | |
| from .mass import Composition, std_aa_mass, Unimod, nist_mass, calculate_mass, std_ion_comp, mass_charge_ratio, std_aa_comp | ||
| from .auxiliary import PyteomicsError, BasicComposition | ||
| from .auxiliary.utils import add_metaclass, memoize | ||
| from .auxiliary.psims_util import load_psimod, load_xlmod, load_gno, obo_cache, _has_psims | ||
| from .auxiliary.psims_util import (load_psimod, load_xlmod, load_gno, load_resid, obo_cache, | ||
| _has_psims) | ||
|
|
||
| try: | ||
| import numpy as np | ||
|
|
@@ -152,6 +153,7 @@ class TagTypeEnum(Enum): | |
| comkp = 13 | ||
| limit = 14 | ||
| custom = 15 | ||
| resid = 16 | ||
|
|
||
| group_placeholder = 999 | ||
|
|
||
|
|
@@ -274,6 +276,7 @@ def is_modification(self) -> bool: | |
| TagTypeEnum.massmod, | ||
| TagTypeEnum.psimod, | ||
| TagTypeEnum.custom, | ||
| TagTypeEnum.resid, | ||
| ) | ||
|
|
||
| def find_modification(self) -> Optional["TagBase"]: | ||
|
|
@@ -872,6 +875,58 @@ def _resolve_impl(self, name=None, id=None, **kwargs): | |
| return rec | ||
|
|
||
|
|
||
| class ResidResolver(ModificationResolver): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want this to be wired into the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Done — So I read your suggestion as the generic chain rather than
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense to me. @mobiusklein is this what you had in mind?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is correct. This is also out of spec but is consistent with the user's expectations.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Working through the chain of events, this might actually break things where it wouldn't before. The scenario is when a user has So we have two, maybe three options:
I think option 1 is the sanest thing to do.
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree 1 is the sanest option. As a potential option 4, we could probably let the chain of trials in
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the |
||
| """Resolve RESID accessions and names. | ||
|
|
||
| RESID identifiers are not numeric (``AA0038``), so unlike the other | ||
| prefixed vocabularies they always arrive as a name rather than an id. | ||
| """ | ||
|
|
||
| def __init__(self, **kwargs): | ||
| super(ResidResolver, self).__init__('resid', **kwargs) | ||
| self._database = kwargs.get("database") | ||
|
|
||
| def load_database(self): | ||
| return load_resid() | ||
|
|
||
| def parse_identifier(self, identifier: str): | ||
| """Strip the CV prefix, tolerating the space the spec writes after it. | ||
|
|
||
| The ProForma specification gives ``EM[R: L-methionine sulfone]...`` as | ||
| an example, so the remainder needs stripping before lookup. | ||
| """ | ||
| name, id = super(ResidResolver, self).parse_identifier(identifier) | ||
| if name is not None: | ||
| name = name.strip() | ||
| return name, id | ||
|
|
||
| def _resolve_impl(self, name=None, id=None, **kwargs): | ||
| if name is not None: | ||
| defn = self.database[name] | ||
| elif id is not None: | ||
| defn = self.database['AA{:04d}'.format(id)] | ||
| else: | ||
| raise ValueError("Must provide one of `name` or `id`") | ||
| mass = defn.monoisotopic_mass | ||
| if mass is None: | ||
| # RESID lists no single mass change for this entry, either because | ||
| # it has none or because the change depends on which residue was | ||
| # modified. Rather than pick one, point at where the alternatives | ||
| # are: each carries the parent residue it applies to. | ||
| raise ModificationMassNotFoundError( | ||
| "RESID gives no single mass for %r; it lists %d corrections, each for a " | ||
| "different parent residue. See `.resolver.database[%r].corrections`." % ( | ||
| (name or id), len(defn.corrections), defn.id)) | ||
| return { | ||
| 'mass': mass, | ||
| 'composition': defn.composition, | ||
| 'name': defn.name, | ||
| 'id': defn.id, | ||
| 'provider': self.name, | ||
| "source": self | ||
| } | ||
|
|
||
|
|
||
| class GenericResolver(ModificationResolver): | ||
|
|
||
| def __init__(self, resolvers, **kwargs): | ||
|
|
@@ -1422,6 +1477,15 @@ class XLMODModification(ModificationBase): | |
| _tag_type = TagTypeEnum.xlmod | ||
|
|
||
|
|
||
| class ResidModification(ModificationBase): | ||
| __slots__ = () | ||
|
|
||
| resolver = ResidResolver() | ||
| prefix_name = "RESID" | ||
| short_prefix = 'R' | ||
| _tag_type = TagTypeEnum.resid | ||
|
|
||
|
|
||
| class CustomModification(ModificationBase): | ||
| __slots__ = () | ||
|
|
||
|
|
@@ -1445,6 +1509,10 @@ class GenericModification(ModificationBase): | |
| PSIModModification.resolver, | ||
| XLMODModification.resolver, | ||
| GNOmeModification.resolver, | ||
| # After the vocabularies that share names with RESID, so anything they | ||
| # already answer keeps its existing answer, and before the non-strict | ||
| # pass so a RESID name is preferred over a fuzzy Unimod match. | ||
| ResidModification.resolver, | ||
| # Some really common names aren't actually found in the XML exactly, so default | ||
| # to non-strict matching now to avoid masking other sources here. | ||
| partial(UnimodModification.resolver, strict=False) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.