1 """Table class for storing Rows
2
3 One base class defines the methods
4 For each BioTable there is a subclass that defines
5 * columns
6 * validations
7 * special method implementations
8 """
9 import csv
10 import copy
11
12 try:
13 import semanticSBML.kegg2sbml
14 kegg2sbml_imported = True
15 except ImportError:
16 kegg2sbml_imported = False
17 except:
18 kegg2sbml_imported = False
19
20 import Row
21 import Column
22 import Exception
23 from libSBtab import GlobalOptions
24 import Warning
25 import Validator
26 import Helper
27
29 """temp function until a correct enzyme regulation parser is implemented"""
30 arr = string.split("*")
31 ret = ""
32 for elem in arr:
33 if elem.startswith("modI"):
34 ret += "".join(["-%s " % splitted_elem for splitted_elem in elem[5:len(elem)-1].split(",")])
35 else:
36 ret += "".join(["+%s " % splitted_elem for splitted_elem in elem[1:len(elem)-1].split(",")])
37 return ret
38
40 """function for comparing two rows by specified attributes
41
42 @param row1: first row
43 @type row1: Row
44 @param row2: second row
45 @type row2: Row
46 @param sort_columns: attribute list which is used for comparison
47 ["name", "number"] will compare first by name and if this is equal by number
48 [("name", "desc"), "number"] will do the same but comparing name will be reversed
49 @type sort_columns: list of (str, tuple of str)
50 @return: +1 if row1 < row2 according to sort_columns
51 -1 if row1 > row2
52 0 if row1 == row2
53 @rtype: int
54 """
55 if sort_columns:
56 sort_column = sort_columns.pop(0)
57 if isinstance(sort_column, tuple):
58 reverse = sort_column[1].lower() == "desc"
59 sort_column = sort_column[0]
60 else:
61 reverse = False
62 return (reverse and -1 or 1) * cmp(row1.attributeGet(sort_column), row2.attributeGet(sort_column)) or eval_sort(row1, row2, sort_columns)
63 else:
64 return 0
65
67 """Base class for all BioTables
68
69 Provides functionality that all table types share
70 """
71
88
93
95 self.columns_mapping.update(columns_mapping)
96
97 - def addReference(self, reference_name, table = None, required = True):
98 reference_name_id = reference_name + "ID"
99 if table is None:
100 try:
101 table = getattr(Table, reference_name + "Table")
102 except AttributeError:
103 table = None
104 self.addColumnsMapping({
105 reference_name : Column.ReferenceName,
106 reference_name_id : Column.ReferenceID,
107 })
108 if required:
109 self.addRequiredColumns((reference_name, reference_name_id))
110 if table:
111 self.addToBeKnown([[reference_name_id, table, "ID"], [reference_name_id, table, reference_name]])
112
114 self.known.add(tuple(sequence))
115
117 self.known.change(tuple(sequence))
118
120 self.required.add(tuple(columns))
121
123 self.required.change(tuple(columns))
124
142
144 """ removes a (all) columns with column_name
145
146 @param column_name: name of the column to be removed
147 @type column_name: str
148 @return: None
149 @return type: None
150 """
151 while column_name in self.first_line:
152 self.first_line.remove(column_name)
153
155 self.first_line = [Column.ColumnProxy(column_name) for column_name in sequence]
156 self.activated_columns = False
157
161
169
171 fobj = string.splitlines()
172 self.fromCSVReader(fobj, append)
173
210
211 - def toTSV(self, filename = None, csv_dialect = None):
212 """Generates tab-seperated-values file from self.rows
213
214 filename will be created or overwritten if existing
215 permissions must be present
216 """
217 if not csv_dialect:
218 csv_dialect = self.getOption("csv_dialect")
219 if not filename:
220 filename = self.filename
221 writer = csv.writer(open(filename, "w"), csv_dialect)
222 writer.writerow(self.first_line)
223 writer.writerows([row.toAttributeList() for row in self])
224
226 """Validates the Table
227
228 Validates the Table by validating each row. Empty table is invalid
229 """
230
231
232
233
234 return all(row.valid() and not row.invalid for row in self.rows)
235
237 return len(self.rows) == 0
238
241
242 - def toSBML(self, outfile = None):
243 """Generates SBML File from this table
244 """
245 raise Exception.exceptions.NotImplementedError("toSBML is only implemented for certain tables classes")
246
255
257 if self.__class__ is not other_table.__class__:
258 raise TypeError("cannot merge a '%s' into a '%s'" % (other_table.className(), self.className()))
259 for row in other_table:
260 new_row = copy.deepcopy(row)
261 self.appendRow(new_row)
262
263 - def updateRow(self, index_or_row, dictionary):
264 """ Updates a row with a dictionary
265
266 @param index_or_row: index(0, 1, ...) or Row Instance that should be updated
267 @type index_or_row: (int, Row)
268 @param dictionary: Dict by which row is updated {attributeName : value, ...}
269 @type dictionary: dict
270 @return: None
271 @rtype: None
272 """
273 self.getRow(index_or_row).updateByDict(dictionary)
274
275 - def appendRow(self, row, auto_set_line_num = True):
276 if row not in self:
277 self.rows.append(row)
278 row.table = self
279 if auto_set_line_num:
280 row.line_num = len(self.rows) + 1
281 else:
282 raise Exception.RowError(row)
283
285 return self.row_class(self)
286
288 """ adds a new Row to the table's rows and optionally updates by dict
289
290 @param dictionary: optional dictionary, which is used to initialize new row
291 @type dictionary: dict
292 @return: the new (and updated) row
293 @rtype: Row
294 """
295 dictionary = dictionary or {}
296 row = self.newRow()
297 row.updateByDict(dictionary)
298 self.appendRow(row)
299 return row
300
302 row = self.getRow(index_or_row)
303 self.rows.remove(row)
304
307
309 return self.getRow(line - 2)
310
311 - def getRow(self, index_or_row):
312 if isinstance(index_or_row, Row.Row):
313 index_or_row = index_or_row.index()
314 return self.rows[index_or_row]
315
316 - def findBy(self, attribute, value, part = None):
317 found = self.getRows({attribute : (part, value)})
318 found.append(None)
319 return found[0]
320
321 - def getRows(self, dictionary = None, **kwds):
322 if dictionary:
323 dictionary = dictionary.copy()
324 else:
325 dictionary = {}
326 dictionary.update(kwds)
327 container = Helper.RowContainer(self.rows)
328 return container.filter(dictionary)
329
331 return self.__class__.__name__
332
334 return self.rows.index(row)
335
341
343 """Iterator over all rows.
344
345 For Syntactic sugar like:
346 for row in table:
347 ...
348 """
349 return self.rows.__iter__()
350
352 return len(self.rows)
353
356
358 if name.startswith("findBy"):
359 return lambda value, part = None: self.findBy(name[6:], value, part)
360 raise AttributeError("%s instance has no attribute '%s'" % (self.className(), name))
361
373
385
398
401 Table.__init__(self, table_pile)
402 self.row_class = Row.Reaction
403 self.addColumnsMapping({
404 "ReactionFormula" : Column.ReactionFormula,
405 "ID" : Column.ReactionID,
406 "Gene" : Column.SimpleString,
407 "EnzymeRegulators" : Column.EnzymeRegulators,
408 "EnzymeRegulationBoolean" : Column.EnzymeRegulationBoolean,
409 "TranscriptionalRegulation" : Column.TranscriptionalRegulation,
410 "TranslationalRegulation" : Column.TranslationalRegulation,
411 "BuildReaction" : Column.BuildElement,
412 "BuildExpression" : Column.BuildElement,
413 })
414 self.addReference("Compartment")
415 self.addRequiredColumns(("ID", "ReactionFormula"))
416
417 - def toSBML(self, outfile = None):
418 """Generates SBML File from this table
419 """
420 if not kegg2sbml_imported:
421 return NotImplemented
422 reactions = []
423 reaction2compartment = {}
424 species2compartment = {}
425
426 if not outfile:
427 outfile = self.filename + ".sbml"
428
429 for row in self:
430 if not row:
431 continue
432 reaction = None
433 if row.nonZero("ID"):
434 reaction = row.get("ID")
435 reaction_str = reaction.id
436 reactions.append(reaction_str)
437 elif row.nonZero("ReactionFormula"):
438 reaction = row.get("ReactionFormula")
439 reaction_str = str(reaction)
440 reactions.append(reaction_str)
441 for reactand in reaction:
442 if reactand.compartment and reactand.different_compartment:
443 species2compartment[reactand.species()] = reactand.compartment
444 reaction2compartment[reaction_str] = row.getSpecifiedOrDefaultCompartment()
445
446 transport_compounds = {}
447 create_modifier_enzymes = True
448 compartment_diffusion = False
449 ncbi_id = 4932
450 mode = 'offline'
451 model_id = 'build_test_model'
452
453
454 reaction2gene = {}
455
456
457 reaction2modifiers = {}
458
459 reaction2metabolic_input_functions = {}
460 reaction2use = {}
461 reaction2transcr_reg = {}
462 abbrevations = {}
463
464 k2s = semanticSBML.kegg2sbml.kegg2sbml( reactions,
465 reaction2compartment = reaction2compartment,
466 species2compartment = species2compartment,
467 transport_compounds = transport_compounds,
468 create_modifier_enzymes = create_modifier_enzymes,
469 compartment_diffusion = compartment_diffusion,
470 ncbi_id = ncbi_id,
471 mode = mode,
472 model_id = model_id,
473 reaction2gene = reaction2gene,
474 reaction2modifiers = reaction2modifiers,
475 reaction2metabolic_input_functions = reaction2metabolic_input_functions,
476 reaction2use = reaction2use,
477 reaction2transcr_reg = reaction2transcr_reg,
478 abbrevations = abbrevations )
479 k2s.writeSBML(outfile)
480
483 Table.__init__(self, table_pile)
484 self.row_class = Row.KineticData
485 self.addColumnsMapping({
486 "Quantity" : Column.SimpleString,
487 "QuantityType" : Column.SimpleString,
488 "Reaction" : Column.SimpleString,
489 "Compound" : Column.SimpleString,
490 "CompoundName" : Column.SimpleString,
491 "CompoundID" : Column.SimpleString,
492 "Value" : Column.Value,
493 "log(Std)" : Column.Value,
494 "Value_Generated" : Column.SimpleString,
495 "Std" : Column.Std,
496 "Mean" : Column.Value,
497 "Unit" : Column.SimpleString,
498 "Compartment" : Column.SimpleString,
499 "Organism" : Column.SimpleString,
500 "Reference" : Column.SimpleString,
501 "ReactionAnnotation" : Column.SimpleString,
502 "ReactionEC" : Column.SimpleString,
503 "EnzymeName" : Column.SimpleString,
504 "EnzymeID" : Column.SimpleString,
505 "CompoundAnnotation" : Column.SimpleString,
506 "ReactionName" : Column.SimpleString,
507 "ReactionSubstrateAnnotation" : Column.SimpleString,
508
509 "SBMLid" : Column.SimpleString,
510 "MathTransformation" : Column.SimpleString,
511 "pH" : Column.SimpleString,
512 "Temperature" : Column.SimpleString,
513 "CompartmentID" : Column.SimpleString,
514 "CompartmentName" : Column.SimpleString,
515 "CompartmentSBMLid" : Column.SimpleString,
516 "CompoundSBMLid" : Column.SimpleString,
517 "ReactionID" : Column.SimpleString,
518 "ReactionSBMLid" : Column.SimpleString,
519 "Enzyme" : Column.SimpleString,
520 "EnzymeSBMLid" : Column.SimpleString,
521 "Gene" : Column.SimpleString,
522 "GeneID" : Column.SimpleString,
523 "GeneName" : Column.SimpleString,
524 "OrganismName" : Column.SimpleString,
525 "OrganismID" : Column.SimpleString,
526 })
527 self.addRequiredColumns(("Reaction", "Compound"), "QuantityType")
528
541
544 self.row_class = Row.Compound
545 EntityTable.__init__(self, table_pile)
546 self.addColumnsMapping({
547 "SumFormula": Column.SimpleString,
548 "StructureFormula" : Column.SimpleString,
549 "Charge" : Column.Charge,
550 "Mass" : Column.Mass,
551 "Components" : Column.SimpleString,
552 "ComponentsFormula" : Column.SimpleString,
553 "IsConstant" : Column.IsConstant,
554 "Split" : Column.Split,
555 })
556 self.addReference("Compartment")
557 self.addReference("State", False)
558 self.addReference("Enzyme")
559 self.addReference("Regulator")
560 self.addRequiredColumns("IsConstant", "Charge", "Mass")
561
573
587
600
611
623
633