/usr/share/mmass/mspy/mod_proteo.py is in mmass 5.1.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | # -------------------------------------------------------------------------
#     Copyright (C) 2005-2012 Martin Strohalm <www.mmass.org>
#     This program is free software; you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation; either version 3 of the License, or
#     (at your option) any later version.
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#     GNU General Public License for more details.
#     Complete text of GNU GPL can be found in the file LICENSE.TXT in the
#     main directory of the program.
# -------------------------------------------------------------------------
# load libs
import re
import itertools
# load stopper
from mod_stopper import CHECK_FORCE_QUIT
# load building blocks
import blocks
# load objects
import obj_sequence
# SEQUENCE DIGESTION
# ------------------
def digest(sequence, enzyme, miscleavage=0, allowMods=False, strict=True):
    """Digest seuence by specified enzyme.
        sequence: (sequence) mspy sequence object
        enzyme: (str) enzyme name - must be defined in mspy.enzymes
        miscleavage: (int) number of allowed misscleavages
        allowMods: (bool) do not care about modifications in cleavage site
        strict: (bool) do not cleave even if variable modification is in cleavage site
    """
    
    # check sequence object
    if not isinstance(sequence, obj_sequence.sequence):
        raise TypeError, "Cannot digest non-sequence object!"
    
    # check cyclic peptides
    if sequence.chainType != 'aminoacids':
        raise TypeError, 'Digest function is not supported for non-amino sequences!'
    
    # check cyclic peptides
    if sequence.cyclic:
        raise TypeError, 'Digest function is not supported for cyclic peptides!'
    
    # check sequence
    if not sequence.chain:
        return []
    
    # get enzyme
    if enzyme in blocks.enzymes:
        enzyme = blocks.enzymes[enzyme]
        expression = re.compile(enzyme.expression+'$')
    else:
        raise KeyError, 'Unknown enzyme! -> ' + enzyme
    
    # get digest indices
    slices = [] # from | to | miscl
    lastIndex = 0
    peptide = ''
    for x, aa in enumerate(sequence):
        
        # check expression
        peptide += aa
        if expression.search(peptide):
            
            # skip not allowed modifications
            if not allowMods and sequence.ismodified(x-1, strict) and not enzyme.modsBefore:
                continue
            elif not allowMods and sequence.ismodified(x, strict) and not enzyme.modsAfter:
                continue
            else:
                slices.append((lastIndex, x, 0))
                lastIndex = x
    
    # add last peptide
    slices.append((lastIndex, x+1, 0))
    
    # add indices for partials
    indices = len(slices)
    for x in range(indices):
        for y in range(1, miscleavage+1):
            if x+y < indices:
                slices.append((slices[x][0], slices[x+y][1], y))
            else:
                break
    
    # get peptides slices from protein
    peptides = []
    for indices in slices:
        
        CHECK_FORCE_QUIT()
        
        # get peptide
        peptide = sequence[indices[0]:indices[1]]
        peptide.miscleavages = indices[2]
        
        # add terminal groups
        if indices[0] != 0:
            peptide.nTermFormula = enzyme.nTermFormula
        if indices[1] != len(sequence):
            peptide.cTermFormula = enzyme.cTermFormula
        
        peptides.append(peptide)
    
    return peptides
# ----
def coverage(ranges, length, human=True):
    """Calculate sequence coverage.
        ranges: (list of mspy.sequence or list of user ranges (start,stop))
        length: (int) parent sequence length
        human: (bool) ranges in human (True) or computer (False) indexes
    """
    
    # check data
    if not ranges:
        return 0.
    
    # make a blank sequence
    blank = length*[0]
    
    # list of ranges
    for r in ranges:
        if human:
            for x in range(r[0]-1, r[1]):
                blank[x]=(1)
        else:
            for x in range(r[0], r[1]):
                blank[x]=(1)
    
    # get sequence coverage
    return 100.0*blank.count(1)/length
# ----
# SEQUENCE FRAGMENTATION
# ----------------------
def fragment(sequence, series, scrambling=False):
    """Generate list of neutral peptide fragments from given peptide.
        sequence: (sequence) mspy sequence object
        series: (list) list of fragment serie names - must be defined in mspy.fragments
        scrambling: (int) allow sequence scrambling
    """
    
    frags = []
    scramblingFilter = ('M')
    
    # check sequence object
    if not isinstance(sequence, obj_sequence.sequence):
        raise TypeError, "Cannot fragment non-sequence object!"
    
    # generate fragments for linear peptide
    if not sequence.cyclic:
        for serie in series:
            frags += fragmentserie(sequence, serie)
    
    # generate fragments for cyclic peptide
    else:
        for peptide in sequence.linearized():
            for serie in series:
                frags += fragmentserie(peptide, serie, cyclicParent=True)
    
    # generate scrambling fragments
    if scrambling:
        buff = []
        for frag in frags:
            
            # check fragment
            if len(frag) <= 2 or not frag.fragmentSerie in ('a', 'b', 'M'):
                continue
            elif frag.fragmentSerie == 'M' and sequence.cyclic:
                continue
            
            # generate fragments
            for peptide in frag.linearized():
                for serie in series:
                    if not serie in scramblingFilter:
                        buff += fragmentserie(peptide, serie, cyclicParent=sequence.cyclic)
        
        frags += buff
    
    # remove same fragments
    buff = []
    have = []
    for frag in frags:
        frhash = [frag.fragmentSerie] + frag.indexes()
        if frag.fragmentSerie == 'M':
            frhash.sort()
        if not frhash in have:
            buff.append(frag)
            have.append(frhash)
    
    frags = buff
    
    return frags
# ----
def fragmentserie(sequence, serie, cyclicParent=False):
    """Generate list of neutral peptide fragments from given peptide.
        sequence: (sequence) mspy sequence object
        serie: (str) fragment serie name - must be defined in mspy.fragments
    """
    
    # check sequence object
    if not isinstance(sequence, obj_sequence.sequence):
        raise TypeError, "Cannot fragment non-sequence object!"
    
    # check cyclic peptides
    if sequence.cyclic:
        raise TypeError, 'Direct fragmentation of cyclic peptides is not supported!'
    
    frags = []
    length = len(sequence)
    
    # get serie definition
    serie = blocks.fragments[serie]
    
    # molecular ion
    if serie.terminus == 'M':
        frag = sequence[:]
        frag.fragmentSerie = serie.name
        frags.append(frag)
    
    # N-terminal fragments
    elif serie.terminus == 'N':
        for x in range(length):
            frag = sequence[:x+1]
            frag.fragmentSerie = serie.name
            frag.fragmentIndex = (x+1)
            frag.cTermFormula = serie.cTermFormula
            frags.append(frag)
            
            CHECK_FORCE_QUIT()
    
    # C-terminal fragments
    elif serie.terminus == 'C':
        for x in range(length):
            frag = sequence[length-(x+1):]
            frag.fragmentSerie = serie.name
            frag.fragmentIndex = (x+1)
            frag.nTermFormula = serie.nTermFormula
            frags.append(frag)
            
            CHECK_FORCE_QUIT()
    
    # singlet fragments
    elif serie.terminus == 'S':
        for x in range(length):
            frag = sequence[x:x+1]
            frag.fragmentSerie = serie.name
            frag.fragmentIndex = (x+1)
            frag.nTermFormula = serie.nTermFormula
            frag.cTermFormula = serie.cTermFormula
            frags.append(frag)
            
            CHECK_FORCE_QUIT()
    
    # internal fragments
    elif serie.terminus == 'I':
        for x in range(1,length-1):
            for y in range(2,length-x):
                frag = sequence[x:x+y]
                frag.fragmentSerie = serie.name
                frag.nTermFormula = serie.nTermFormula
                frag.cTermFormula = serie.cTermFormula
                frags.append(frag)
                
                CHECK_FORCE_QUIT()
    
    # correct termini for cyclic peptides
    if cyclicParent:
        for frag in frags:
            if serie.terminus == 'M':
                frag.nTermFormula = ''
                frag.cTermFormula = ''
            elif serie.terminus == 'N':
                frag.nTermFormula = 'H'
            elif serie.terminus == 'C':
                frag.cTermFormula = 'H-1'
    
    # remove nonsense terminal fragments
    if serie.terminus == 'N':
        if frags and serie.nTermFilter:
            del frags[0]
        if frags and serie.cTermFilter:
            del frags[-1]
    elif serie.terminus == 'C':
        if frags and serie.nTermFilter:
            del frags[-1]
        if frags and serie.cTermFilter:
            del frags[0]
    elif serie.terminus == 'S':
        if frags and serie.nTermFilter:
            del frags[0]
        if frags and serie.cTermFilter:
            del frags[-1]
    
    return frags
# ----
def fragmentlosses(fragments, losses=[], defined=False, limit=1, filterIn={}, filterOut={}):
    """Apply specified neutral losses to fragments.
        fragments: (list) list of sequence fragments
        losses: (list) list of neutral losses
        defined: (bool) use monomer-defined neutral losses
        limit: (int) max length of loss combination
        filterIn: (dic) allowed series for specified losses
        filterOut: (dic) not allowed series for specified losses
    """
    
    # make losses combinations
    combinations = []
    for x in range(1, min(len(losses), limit) + 1):
        for c in itertools.combinations(losses, x):
            combinations.append(list(c))
    
    # generate fragments
    buff = []
    for frag in fragments:
        
        CHECK_FORCE_QUIT()
        
        # get monomer-defined losses to check specifity
        definedLosses = []
        for monomer in frag:
            definedLosses += blocks.monomers[monomer].losses
        
        # append new combinations with monomer-defined losses
        lossesToApply = combinations[:]
        if defined:
            for monomer in frag:
                for item in ([[]] + lossesToApply[:]):
                    for loss in blocks.monomers[monomer].losses:
                        newItem = item + [loss]
                        newItem.sort()
                        
                        if not [loss] in lossesToApply:
                            lossesToApply.append([loss])
                        if len(newItem) <= limit and not newItem in lossesToApply:
                            lossesToApply.append(newItem)
        
        # make fragment
        for combination in lossesToApply:
            newFrag = frag.duplicate()
            skip = False
            
            # apply losses
            for loss in combination:
                newFrag.fragmentLosses.append(loss)
                
                # check neutral gains
                if loss in frag.fragmentGains:
                    skip = True
                    break
                
                # check fragment type filter
                if (loss in filterOut and frag.fragmentSerie in filterOut[loss]) \
                    or (loss in filterIn and not frag.fragmentSerie in filterIn[loss]):
                    skip = True
                    break
                
                # check fragment composition
                if not newFrag.isvalid():
                    skip = True
                    break
                
                # filter non-specific losses
                if not loss in definedLosses:
                    newFrag.fragmentFiltered = True
            
            # store fragment
            if not skip:
                buff.append(newFrag)
    
    return buff
# ----
def fragmentgains(fragments, gains=[], filterIn={'H2O':['b'], 'CO':['b', 'c', 'break']}, filterOut={}):
    """Apply specified neutral gains to fragments.
        fragments: (list) list of sequence fragments
        gains: (list) list of neutral gains
        filterIn: (dic) allowed series for specified gains
        filterOut: (dic) not allowed series for specified gains
    """
    
    # generate fragments
    buff = []
    for frag in fragments:
        
        CHECK_FORCE_QUIT()
        
        # is parent cyclic?
        cyclicParent = False
        for item in frag.history:
            if 'break' in item:
                cyclicParent = True
                break
        
        # apply gains
        for gain in gains:
            
            # check neutral losses
            if gain in frag.fragmentLosses:
                continue
            
            # check fragment type filters
            if (gain in filterOut and frag.fragmentSerie in filterOut[gain]) \
                or (gain in filterIn and not frag.fragmentSerie in filterIn[gain]):
                continue
            
            # check break (cyclic parent)
            if gain in filterIn and 'break' in filterIn[gain] and not cyclicParent:
                continue
            
            # make fragment
            newFrag = frag.duplicate()
            newFrag.fragmentGains.append(gain)
            
            # check fragment composition
            if not newFrag.isvalid():
                continue
            
            # store fragment
            buff.append(newFrag)
    
    return buff
# ----
  
 |