1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """The TagCategory base class."""
24
25
26 from numpy import float64, ndarray, zeros
27 from warnings import warn
28
29
30 from bmrblib.misc import no_missing, translate
31 from bmrblib.pystarlib.SaveFrame import SaveFrame
32 from bmrblib.pystarlib.TagTable import TagTable
33 from bmrblib.version import Star_version; version = Star_version()
34
35
37 """The base class for the saveframe classes."""
38
40 """Initialise the class, placing the pystarlib data nodes into the namespace.
41
42 @param datanodes: The pystarlib data nodes object.
43 @type datanodes: list
44 """
45
46
47 self.datanodes = datanodes
48
49
50 self.count = 0
51
52
53 self.tag_categories = CategoryList()
54 self.add_tag_categories()
55
56
57 - def add(self, **keywords):
58 """Add data to the saveframe.
59
60 If the keywords are within the tag dictionary structure as the variable name, then the data will be checked, translated and stored in that variable. If not, then a warning will be given.
61
62 @return: The saveframe count.
63 @rtype: int
64 """
65
66
67 self.reset()
68
69
70 for cat in self.tag_categories:
71
72 for key in cat._key_list:
73
74 if not cat[key].var_name or not cat[key].default:
75 continue
76
77
78 setattr(self, cat[key].var_name, translate(cat[key].default))
79
80
81 for name, val in keywords.items():
82
83 info = self.tag_categories.get_tag(name)
84
85
86 if not info:
87 setattr(self, name, val)
88 continue
89
90
91 cat_index, key, obj = info
92
93
94 if not obj.missing:
95 no_missing(val, name)
96
97
98 if obj.allowed != None:
99
100 if not (isinstance(val, list) and not isinstance(val, ndarray)):
101 val_list = [val]
102 else:
103 val_list = val
104
105
106 for i in range(len(val_list)):
107 if val_list[i] not in obj.allowed:
108 raise NameError("The %s keyword argument of '%s' must be one of %s." % (name, val_list[i], obj.allowed))
109
110
111 if (isinstance(val, list) or isinstance(val, ndarray)):
112
113 N = self.tag_categories[cat_index]._N()
114
115
116 if N == None:
117 pass
118
119
120 if N != None and len(val) != N:
121 raise NameError("The number of elements in the %s keyword argument should be N = %s." % (name, N))
122
123
124 setattr(self, name, translate(val))
125
126
127 self.count = self.count + 1
128 self.count_str = str(self.count)
129
130
131 for i in range(len(self.tag_categories)):
132 ids = self.tag_categories[i].generate_data_ids()
133 if ids:
134 self.data_ids = translate(ids)
135
136
137 self.pre_ops()
138
139
140 self.frame = SaveFrame(title=self.create_title())
141
142
143 for i in range(len(self.tag_categories)):
144 self.tag_categories[i].create()
145
146
147 self.datanodes.append(self.frame)
148
149
150 return self.count
151
152
154 """Create the saveframe title.
155
156 @return: The title.
157 @rtype: str
158 """
159
160
161 if hasattr(self, 'label'):
162 return self.label + '_' + self.count_str
163 else:
164 return self.sf_label + '_' + self.count_str
165
166
168 """Read all the tags from the datanodes.
169
170 @keyword datanode: The datanode.
171 @type datanode: Datanode instance
172 @return: The data.
173 @rtype: tuple
174 """
175
176
177 mapping = self.find_mapping(datanode)
178
179
180 for i in range(len(mapping)):
181
182 if mapping[i] == None:
183 continue
184
185
186 self.tag_categories[mapping[i]].extract_tag_data(datanode.tagtables[i])
187
188
189 if version.major == 2:
190 self.sf_framecode = datanode.title
191
192
194 """Determine the mapping between the tag categories of the NMR-STAR file and the bmrblib class.
195
196 @keyword datanode: The datanode.
197 @type datanode: Datanode instance
198 @return: The mapping structure.
199 @rtype: list
200 """
201
202
203 N = len(self.tag_categories)
204 M = len(datanode.tagtables)
205 counts = zeros((M, N), float64)
206 mapping = []
207
208
209 for table_ind in range(M):
210 for cat_ind in range(N):
211
212 cat = self.tag_categories[cat_ind]
213 table = datanode.tagtables[table_ind]
214
215
216 for key in cat.keys():
217 for name in table.tagnames:
218
219 if name == cat[key].tag_name_full():
220 counts[table_ind, cat_ind] += 1
221
222
223 if not counts[table_ind].sum():
224 index = None
225 else:
226 index = counts[table_ind].tolist().index(counts[table_ind].max())
227 mapping.append(index)
228
229
230 return mapping
231
232
234 """Loop over the saveframes, yielding the data.
235
236 @return: The saveframe data.
237 @rtype: tuple
238 """
239
240
241 for i in range(len(self.tag_categories)):
242 self.tag_categories[i].tag_setup()
243
244
245 sf_name = getattr(self, 'sf_label')
246
247
248 for datanode in self.datanodes:
249
250 found = False
251 for index in range(len(datanode.tagtables[0].tagnames)):
252
253 if datanode.tagtables[0].tagnames[index] == self.tag_categories[0]['SfCategory'].tag_name_full():
254
255 if datanode.tagtables[0].tagvalues[index][0] == sf_name:
256 found = True
257 break
258
259
260 if not found:
261 continue
262
263
264 self.extract_data(datanode)
265
266
267 yield self.read()
268
269
271 """A dummy method for performing no saveframe specific operations prior to XML creation."""
272
273
275 """Read all the data from the saveframe.
276
277 @return: A dictionary of all the data.
278 @rtype: dict
279 """
280
281
282 data = {}
283
284
285 for cat in self.tag_categories:
286
287 for key in cat._key_list:
288
289 if not cat[key].var_name:
290 continue
291
292
293 if not hasattr(self, cat[key].var_name):
294 obj = None
295
296
297 else:
298 obj = getattr(self, cat[key].var_name)
299
300
301 data[cat[key].var_name] = translate(obj, format=cat[key].format, reverse=True)
302
303
304 return data
305
306
308 """Reset all data structures to None."""
309
310
311 for cat in self.tag_categories:
312
313 for key in cat._key_list:
314
315 if not cat[key].var_name or not hasattr(self, cat[key].var_name):
316 continue
317
318
319 if cat[key].var_name in ['sf_label', 'count', 'count_str']:
320 continue
321
322
323 setattr(self, cat[key].var_name, translate(None))
324
325
327 """Special class for when BMRB saveframes are non-existent in certain NMR-STAR versions."""
328
330 """Initialise the special class.
331
332 @param name: The name of the missing Saveframe.
333 @type name: str
334 """
335
336
337 self.name = name
338
339
340 - def add(self, *args, **keywords):
341 """Special function for giving a warning."""
342
343
344 warn(Warning("The %s saveframe does not exist in this NMR-STAR version." % self.name))
345
346
348 """Special function for giving a warning."""
349
350
351 warn(Warning("The %s saveframe does not exist in this NMR-STAR version." % self.name))
352
353
354 yield None
355
356
357
358
360 """A special lits object for holding the different saveframe tag categories."""
361
363 """Return the tag object possessing the given variable name.
364
365 @param var_name: The variable name.
366 @type var_name: str
367 @return: The key and tag objects.
368 @rtype: str, TagObject instance
369 """
370
371
372 for i in range(len(self)):
373
374 for key, obj in self[i].items():
375 if var_name == obj.var_name:
376 return i, key, obj
377
378
379
381 """A special dictionary object for creating the tag translation tables."""
382
384 """Set up the table."""
385
386
387 super(TagTranslationTable, self).__init__()
388
389
390 self.N = None
391
392
393 self._key_list = []
394
395
396 - def add(self, key, var_name=None, tag_name=None, allowed=None, default=None, format='str', missing=True):
397 """Add an entry to the translation table.
398
399 @keyword key: The dictionary key. This is also the BMRB NMR-STAR database table name.
400 @type key: str
401 @keyword var_name: The saveframe variable name corresponding to the key.
402 @type var_name: None or str
403 @keyword tag_name: The BMRB NMR-STAR tag name corresponding to the key.
404 @type tag_name: None or str
405 @keyword allowed: A list of allowable values for the data.
406 @type allowed: None or list
407 @keyword default: The default value.
408 @type default: anything
409 @keyword format: The original python format of the data.
410 @type format: str
411 @keyword missing: A flag which if True will allow the data to be set to None.
412 @type missing: bool
413 """
414
415
416 if key in self._key_list:
417
418 self[key].allowed = allowed
419 self[key].missing = missing
420 self[key].tag_name = tag_name
421 self[key].var_name = var_name
422 self[key].default = default
423 self[key].format = format
424
425
426 self._key_list.remove(key)
427 self._key_list.append(key)
428
429
430 else:
431
432 self[key] = TagObject(self, var_name=var_name, tag_name=tag_name, allowed=allowed, default=default, format=format, missing=missing)
433
434
435 self._key_list.append(key)
436
437
438
440 """An object for filling the translation table."""
441
442 - def __init__(self, category, var_name=None, tag_name=None, allowed=None, default=None, format='str', missing=True):
443 """Setup the internal variables.
444
445 This stores the variable name, BMRB NMR-STAR tag name, a list of allowable values, the missing flag, and any other tag specific information corresponding to the key.
446
447 @param category: The parent tag category class object.
448 @type category: TagTranslationTable instance
449 @keyword var_name: The saveframe variable name corresponding to the key.
450 @type var_name: None or str
451 @keyword tag_name: The BMRB NMR-STAR tag name corresponding to the key.
452 @type tag_name: None or str
453 @keyword allowed: A list of allowable values for the data.
454 @type allowed: None or list
455 @keyword default: The default value.
456 @type default: anything
457 @keyword format: The original python format of the data.
458 @type format: str
459 @keyword missing: A flag which if True will allow the data to be set to None.
460 @type missing: bool
461 """
462
463
464 self.category = category
465
466
467 self.allowed = allowed
468 self.missing = missing
469 self.tag_name = tag_name
470 self.var_name = var_name
471 self.default = default
472 self.format = format
473
474
476 """Add the prefix to the tag name and return the full tag name.
477
478 @return: The full tag name with prefix.
479 @rtype: str
480 """
481
482
483 if not self.tag_name:
484 return None
485 else:
486 return self.category.tag_prefix + self.tag_name
487
488
489
491 """The base class for tag category classes."""
492
493
494 tag_category_label = None
495
496
497 free = False
498
500 """Initialise the tag category object, placing the saveframe into its namespace.
501
502 @param sf: The saveframe object.
503 @type sf: saveframe instance
504 """
505
506
507 super(TagCategory, self).__init__()
508
509
510 self.sf = sf
511
512
513 self.tag_category_label = None
514
515
517 """Determine the length of the variables.
518
519 @return: The length.
520 @rtype: int
521 """
522
523
524 N = None
525 for key in self.keys():
526
527 if self[key].var_name and hasattr(self.sf, self[key].var_name):
528
529 obj = getattr(self.sf, self[key].var_name)
530
531
532 if not isinstance(obj, list) and not isinstance(obj, ndarray):
533 continue
534
535
536 N = len(obj)
537 break
538
539
540 if N:
541 self.N = N
542
543
544 return N
545
546
548 """Create the tag category."""
549
550
551 self.tag_setup()
552 tag_names = []
553 tag_values = []
554
555
556 if self.is_empty():
557 return
558
559
560 for key in self._key_list:
561
562 if self[key].tag_name != None and self[key].var_name != None:
563
564 tag_names.append(self[key].tag_name_full())
565
566
567 if hasattr(self.sf, self[key].var_name):
568 val = getattr(self.sf, self[key].var_name)
569 else:
570 val = translate(None)
571
572
573 if not isinstance(val, list):
574 val = [val]
575
576
577 tag_values.append(val)
578
579
580 if not len(tag_names):
581 return
582
583
584 N = len(tag_values[0])
585 for i in range(len(tag_values)):
586 if len(tag_values[i]) > N:
587
588 if N != 1:
589 raise NameError("The tag values are not all the same length '%s'." % tag_values)
590
591
592 N = len(tag_values[i])
593
594
595 for i in range(len(tag_values)):
596 if len(tag_values[i]) == 1:
597 tag_values[i] = tag_values[i] * N
598
599
600 table = TagTable(free=self.free, tagnames=tag_names, tagvalues=tag_values)
601
602
603 self.sf.frame.tagtables.append(table)
604
605
607 """Extract all of the tag data from the tagtable, placing it into the designated variable names.
608
609 @param tagtable: The tagtable.
610 @type tagtable: Tagtable instance
611 """
612
613
614 for key in self._key_list:
615
616 if self[key].tag_name_full() not in tagtable.tagnames:
617 continue
618
619
620 if self[key].var_name == None:
621 continue
622
623
624 index = tagtable.tagnames.index(self[key].tag_name_full())
625
626
627 data = tagtable.tagvalues[index]
628
629
630 if self.free:
631 data = data[0]
632
633
634 setattr(self.sf, self[key].var_name, data)
635
636
638 """Generate the data ID structure.
639
640 @keyword N: The number of data points.
641 @type N: int
642 """
643
644
645 N = self._N()
646
647
648 if not N:
649 return
650
651
652 return list(range(1, N+1))
653
654
656 """Dummy method for check if the tag category is empty.
657
658 @return: The state of emptiness (False).
659 @rtype: bool
660 """
661
662
663 return False
664
665
666 - def tag_setup(self, tag_category_label=None, sep=None):
667 """Setup the tag names.
668
669 @keyword tag_category_label: The tag name prefix specific for the tag category.
670 @type tag_category_label: None or str
671 @keyword sep: The string separating the tag name prefix and suffix.
672 @type sep: str
673 """
674
675
676 if tag_category_label:
677 self.tag_category_label = tag_category_label
678 if sep:
679 self.sep = sep
680 else:
681 self.sep = '.'
682
683
684 self.tag_prefix = '_'
685 if self.tag_category_label:
686 self.tag_prefix = self.tag_prefix + self.tag_category_label + self.sep
687
688
689
691 """The free version of the TagCategory class."""
692
693
694 free = True
695
697 """Setup the TagCategoryFree tag category.
698
699 @param sf: The saveframe object.
700 @type sf: saveframe instance
701 """
702
703
704 super(TagCategoryFree, self).__init__(sf)
705
706
707 self.add(key='SfCategory', var_name='sf_label', tag_name='Saveframe_category')
708 self.add(key='SfFramecode', var_name='sf_framecode', tag_name=None)
709