4
4
5
5
from functools import reduce , total_ordering
6
6
from pyparsing import (Literal , nums , Word , Forward , Optional , Regex ,
7
- infixNotation , delimitedList , opAssoc )
7
+ infixNotation , delimitedList , opAssoc , alphas )
8
8
from pyvdrm .drm import AsiExpr , AsiBinaryExpr , AsiUnaryExpr , DRMParser
9
9
from pyvdrm .vcf import MutationSet
10
10
11
+ def update_flags (fst , snd ):
12
+ for k in snd :
13
+ if k in fst :
14
+ fst [k ].append (snd [k ])
15
+ else :
16
+ fst [k ] = snd [k ] # this chould be achieved with a defaultdict
17
+ return fst
18
+
11
19
12
20
def maybe_foldl (func , noneable ):
13
21
"""Safely fold a function over a potentially empty list of
@@ -42,22 +50,28 @@ class Score(object):
42
50
43
51
residues = set ([])
44
52
score = None
45
- flags = [] # allow a score expression to raise a user defined string
53
+ flags = {} # allow a score expression to raise a user defined string
46
54
47
- def __init__ (self , score , residues ):
55
+ def __init__ (self , score , residues , flags = {} ):
48
56
""" Initialize.
49
57
50
58
:param bool|float score: value of the score
51
59
:param residues: sequence of Mutations
60
+ :param flags: dictionary of user defined strings and supporting Mutations
52
61
"""
53
62
self .score = score
54
63
self .residues = set (residues )
64
+ self .flags = flags
55
65
56
66
def __add__ (self , other ):
57
- return Score (self .score + other .score , self .residues | other .residues )
67
+ flags = update_flags (self .flags , other .flags )
68
+ return Score (self .score + other .score , self .residues | other .residues ,
69
+ flags )
58
70
59
71
def __sub__ (self , other ):
60
- return Score (self .score - other .score , self .residues | other .residues )
72
+ flags = update_flags (self .flags , other .flags )
73
+ return Score (self .score - other .score , self .residues | other .residues ,
74
+ flags )
61
75
62
76
def __repr__ (self ):
63
77
return "Score({!r}, {!r})" .format (self .score , self .residues )
@@ -155,14 +169,23 @@ class ScoreExpr(AsiExpr):
155
169
"""Score expressions propagate DRM scores"""
156
170
157
171
def __call__ (self , mutations ):
158
- if len (self .children ) == 3 :
172
+
173
+ flags = {}
174
+ if len (self .children ) == 4 :
175
+ operation , _ , flag , _ = self .children
176
+ flags [flag ] = []
177
+ score = 0 # should be None
178
+
179
+ elif len (self .children ) == 3 :
159
180
operation , minus , score = self .children
160
- if minus != '-' :
181
+ if minus != '-' : # this is parsing the expression twice, refactor
161
182
raise ValueError
162
183
score = - 1 * int (score )
184
+
163
185
elif len (self .children ) == 2 :
164
186
operation , score = self .children
165
187
score = int (score )
188
+
166
189
else :
167
190
raise ValueError
168
191
@@ -173,7 +196,7 @@ def __call__(self, mutations):
173
196
174
197
if result .score is False :
175
198
return Score (0 , [])
176
- return Score (score , result .residues )
199
+ return Score (score , result .residues , flags = flags )
177
200
178
201
179
202
class ScoreList (AsiExpr ):
@@ -262,6 +285,9 @@ def parser(self, rule):
262
285
notmorethan = Literal ('NOTMORETHAN' )
263
286
l_par = Literal ('(' ).suppress ()
264
287
r_par = Literal (')' ).suppress ()
288
+
289
+ quote = Literal ('"' )
290
+
265
291
mapper = Literal ('=>' ).suppress ()
266
292
integer = Word (nums )
267
293
@@ -302,7 +328,8 @@ def parser(self, rule):
302
328
[(and_ , 2 , opAssoc .LEFT , AndExpr ),
303
329
(or_ , 2 , opAssoc .LEFT , OrExpr )]) | condition
304
330
305
- scoreitem = booleancondition + mapper + Optional (Literal ('-' )) + integer
331
+ score = Optional (Literal ('-' )) + integer | quote + Word (alphas ) + quote
332
+ scoreitem = booleancondition + mapper + score
306
333
scoreitem .setParseAction (ScoreExpr )
307
334
scorelist = max_ + l_par + delimitedList (scoreitem ) + r_par | \
308
335
delimitedList (scoreitem )
0 commit comments