pidibble 1.3.2__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {pidibble-1.3.2 → pidibble-1.4.0}/PKG-INFO +5 -1
  2. {pidibble-1.3.2 → pidibble-1.4.0}/README.md +4 -0
  3. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/mmcif_parse.py +8 -7
  4. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/pdbparse.py +10 -8
  5. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/pdbrecord.py +74 -1
  6. {pidibble-1.3.2 → pidibble-1.4.0}/pyproject.toml +1 -1
  7. {pidibble-1.3.2 → pidibble-1.4.0}/.github/workflows/release.yaml +0 -0
  8. {pidibble-1.3.2 → pidibble-1.4.0}/.gitignore +0 -0
  9. {pidibble-1.3.2 → pidibble-1.4.0}/.readthedocs.yaml +0 -0
  10. {pidibble-1.3.2 → pidibble-1.4.0}/LICENSE +0 -0
  11. {pidibble-1.3.2 → pidibble-1.4.0}/MANIFEST.in +0 -0
  12. {pidibble-1.3.2 → pidibble-1.4.0}/docs/Makefile +0 -0
  13. {pidibble-1.3.2 → pidibble-1.4.0}/docs/make.bat +0 -0
  14. {pidibble-1.3.2 → pidibble-1.4.0}/docs/requirements.txt +0 -0
  15. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/_static/css/custom.css +0 -0
  16. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/API.rst +0 -0
  17. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.baseparsers.rst +0 -0
  18. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.baserecord.rst +0 -0
  19. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.hex.rst +0 -0
  20. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.mmcif_parse.rst +0 -0
  21. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.pdbparse.rst +0 -0
  22. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.pdbrecord.rst +0 -0
  23. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.resources.rst +0 -0
  24. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/api/pidibble.rst +0 -0
  25. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/conf.py +0 -0
  26. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/index.rst +0 -0
  27. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/installation.rst +0 -0
  28. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/notes.md +0 -0
  29. {pidibble-1.3.2 → pidibble-1.4.0}/docs/source/usage.rst +0 -0
  30. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/__init__.py +0 -0
  31. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/baseparsers.py +0 -0
  32. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/baserecord.py +0 -0
  33. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/hex.py +0 -0
  34. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/resources/__init__.py +0 -0
  35. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/resources/mmcif_format.yaml +0 -0
  36. {pidibble-1.3.2 → pidibble-1.4.0}/pidibble/resources/pdb_format.yaml +0 -0
  37. {pidibble-1.3.2 → pidibble-1.4.0}/tests/__init__.py +0 -0
  38. {pidibble-1.3.2 → pidibble-1.4.0}/tests/conftest.py +0 -0
  39. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_hex/my_system.pdb +0 -0
  40. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_hex.py +0 -0
  41. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/4tvp.cif +0 -0
  42. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/4tvp.pdb +0 -0
  43. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/4zmj-newresnames.pdb +0 -0
  44. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/4zmj.cif +0 -0
  45. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/4zmj.pdb +0 -0
  46. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/6m0j.pdb +0 -0
  47. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/8fae.cif +0 -0
  48. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/G.pdb +0 -0
  49. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/GG.pdb +0 -0
  50. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/test.pdb +0 -0
  51. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb/test_pdb_format.yaml +0 -0
  52. {pidibble-1.3.2 → pidibble-1.4.0}/tests/unit/test_rcsb.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pidibble
3
- Version: 1.3.2
3
+ Version: 1.4.0
4
4
  Summary: A complete Protein Data Bank (PDB) file parser
5
5
  Project-URL: Source, https://github.com/cameronabrams/pidibble
6
6
  Project-URL: Documentation, https://pidibble.readthedocs.io/en/latest/
@@ -91,6 +91,10 @@ ATOM
91
91
  ```
92
92
 
93
93
  ## Release History
94
+ * 1.4.0
95
+ * Introduced `PDBRecordList` and `PDBRecordDict` classes
96
+ * 1.3.3
97
+ * fixed bugs regarding assuming missing records actually present in mmcif parsing
94
98
  * 1.3.2
95
99
  * implemented `filepath` parameter in `PDBParser()` to make
96
100
  reading local files more transparent
@@ -73,6 +73,10 @@ ATOM
73
73
  ```
74
74
 
75
75
  ## Release History
76
+ * 1.4.0
77
+ * Introduced `PDBRecordList` and `PDBRecordDict` classes
78
+ * 1.3.3
79
+ * fixed bugs regarding assuming missing records actually present in mmcif parsing
76
80
  * 1.3.2
77
81
  * implemented `filepath` parameter in `PDBParser()` to make
78
82
  reading local files more transparent
@@ -9,7 +9,7 @@
9
9
  """
10
10
 
11
11
  from collections import UserDict
12
- from .pdbrecord import PDBRecord
12
+ from .pdbrecord import PDBRecord, PDBRecordDict, PDBRecordList
13
13
  from .baserecord import BaseRecord
14
14
  import logging
15
15
  logger=logging.getLogger(__name__)
@@ -214,8 +214,9 @@ class MMCIF_Parser:
214
214
  spawns_on=mapspec.get('spawns_on',None)
215
215
  allcaps=mapspec.get('allcaps',[])
216
216
  if_dot_replace_with=mapspec.get('if_dot_replace_with',{})
217
+ logger.debug(f'getting cifrec for {mapspec["data_obj"]}')
217
218
  cifrec=self.cif_data.getObj(mapspec['data_obj'])
218
- if not tables:
219
+ if not tables and cifrec is not None:
219
220
  for idx in range(len(cifrec)):
220
221
  if not use_signal or (cifrec.getValue(sigattr,idx)==sigval):
221
222
  if global_maps:
@@ -334,18 +335,18 @@ class MMCIF_Parser:
334
335
 
335
336
  Returns
336
337
  -------
337
- dict
338
- A dictionary where keys are record types and values are lists of :class:`pdbrecord.sPDBRecord` instances.
338
+ PDBRecordDict
339
+ A dictionary where keys are record types and values are lists of :class:`pdbrecord.PDBRecord` instances.
339
340
  """
340
- recdict={}
341
+ recdict=PDBRecordDict()
341
342
  for rectype,mapspec in self.formats.items():
342
343
  idicts=self.gen_dict(mapspec)
343
344
  for idict in idicts:
344
345
  this_key=idict.get('tmp_label','')
345
346
  reckey=rectype if not this_key else f'{rectype}.{this_key}'
346
347
  if reckey in recdict:
347
- if not type(recdict[reckey])==list:
348
- recdict[reckey]=[recdict[reckey]]
348
+ if not type(recdict[reckey])==PDBRecordList:
349
+ recdict[reckey]=PDBRecordList([recdict[reckey]])
349
350
  idict['key']=reckey
350
351
  recdict[reckey].append(PDBRecord(idict))
351
352
  else:
@@ -14,10 +14,11 @@ import yaml
14
14
  import numpy as np
15
15
  from pathlib import Path
16
16
  from mmcif.io.IoAdapterCore import IoAdapterCore
17
+ from typing import List, Dict
17
18
  from . import resources
18
19
  from .baseparsers import ListParsers, ListParser, str2int_sig, safe_float
19
20
  from .baserecord import BaseRecordParser
20
- from .pdbrecord import PDBRecord
21
+ from .pdbrecord import PDBRecord, PDBRecordDict, PDBRecordList
21
22
  from .mmcif_parse import MMCIF_Parser
22
23
  from pidibble import resources
23
24
  logger=logging.getLogger(__name__)
@@ -35,9 +36,10 @@ class PDBParser:
35
36
 
36
37
  Attributes
37
38
  ----------
38
-
39
- parsed : dict
40
- A dictionary to store parsed records, where keys are record types and values are lists of :class:`.pdbrecord.PDBRecord` instances. Empty if no input file is provided.
39
+
40
+ parsed : PDBRecordDict
41
+ A dictionary containing parsed records, where keys are record types and values are :class:`.pdbrecord.PDBRecord` instances or lists of instances.
42
+ This dictionary is populated after parsing the PDB or mmCIF file.
41
43
 
42
44
  mappers : dict
43
45
  A dictionary of mappers for parsing different data types, including custom formats and delimiters.
@@ -75,7 +77,7 @@ class PDBParser:
75
77
  self.pdb_lines=[]
76
78
  self.cif_data={}
77
79
 
78
- self.parsed={}
80
+ self.parsed=PDBRecordDict()
79
81
  self.pdb_format_file=pdb_format_file
80
82
  if not os.path.isfile(self.pdb_format_file):
81
83
  # if pdb_format_file is not a file in the CWD, assume it is a relative path to the resources directory
@@ -262,7 +264,7 @@ class PDBParser:
262
264
  if tok[0]==group_open_record.key:
263
265
  groupid=getattr(group_open_record,tok[1])
264
266
  setattr(new_record,group_open_record.key.lower(),groupid)
265
- self.parsed[key]=[new_record]
267
+ self.parsed[key]=PDBRecordList([new_record])
266
268
  else:
267
269
  # this is either
268
270
  # (a) a continuation record of a given key.(determinants)
@@ -328,7 +330,7 @@ class PDBParser:
328
330
  rf=p.format
329
331
  if 'embedded_records' in rf:
330
332
  new_parsed_records.update(p.parse_embedded(self.pdb_format_dict['record_formats'],self.mappers))
331
- elif type(p)==list:
333
+ elif type(p)==PDBRecordList:
332
334
  for q in p:
333
335
  rf=q.format
334
336
  if 'embedded_records' in rf:
@@ -361,7 +363,7 @@ class PDBParser:
361
363
  It updates the :attr:`PDBParser.parsed` dictionary with the new parsed records.
362
364
  """
363
365
  for key,p in self.parsed.items():
364
- if type(p)==list:
366
+ if type(p)==PDBRecordList:
365
367
  continue # don't expect to read a table from a multiple-record entry
366
368
  rf=p.format
367
369
  if 'tables' in rf:
@@ -7,7 +7,7 @@
7
7
  .. moduleauthor: Cameron F. Abrams, <cfa22@drexel.edu>
8
8
 
9
9
  """
10
-
10
+ from collections import UserList, UserDict
11
11
  from .baserecord import BaseRecord, BaseRecordParser
12
12
  from .baseparsers import StringParser
13
13
  import logging
@@ -442,6 +442,79 @@ class PDBRecord(BaseRecord):
442
442
  if not all([x=='' for x in parsedrow.__dict__.values()]):
443
443
  self.tables[tname].append(parsedrow)
444
444
 
445
+ class PDBRecordList(UserList):
446
+ """
447
+ A class representing a list of PDBRecord instances, inheriting from UserList.
448
+ It provides methods for parsing and handling multiple PDB records.
449
+ """
450
+ def __init__(self, initlist=None):
451
+ if initlist is not None:
452
+ self._validate_all(initlist)
453
+ super().__init__(initlist or [])
454
+
455
+ def _validate(self, item):
456
+ if not isinstance(item, PDBRecord):
457
+ raise TypeError(f"All items must be instances of PDBRecord, got {type(item)}")
458
+
459
+ def _validate_all(self, iterable):
460
+ for item in iterable:
461
+ self._validate(item)
462
+
463
+ def __setitem__(self, index, item):
464
+ # Support slice assignment
465
+ if isinstance(index, slice):
466
+ self._validate_all(item)
467
+ else:
468
+ self._validate(item)
469
+ super().__setitem__(index, item)
470
+
471
+ def append(self, item):
472
+ self._validate(item)
473
+ super().append(item)
474
+
475
+ def insert(self, index, item):
476
+ self._validate(item)
477
+ super().insert(index, item)
478
+
479
+ def extend(self, other):
480
+ self._validate_all(other)
481
+ super().extend(other)
482
+
483
+ def __add__(self, other):
484
+ self._validate_all(other)
485
+ return AList(super().__add__(other))
486
+
487
+ def __iadd__(self, other):
488
+ self._validate_all(other)
489
+ return super().__iadd__(other)
490
+
491
+ class PDBRecordDict(UserDict):
492
+ """
493
+ A class representing a dictionary of PDBRecord or PDBRecordList instances, inheriting from UserDict.
494
+ It provides methods for parsing and handling multiple PDB records stored in a dictionary.
495
+ """
496
+ def __init__(self, *args, **kwargs):
497
+ super().__init__()
498
+ self.update(*args, **kwargs)
499
+
500
+ def _validate(self, value):
501
+ if not isinstance(value, (PDBRecord, PDBRecordList)):
502
+ raise TypeError(f"Values must be PDBRecord or PDBRecordList, got {type(value)}")
503
+
504
+ def __setitem__(self, key, value):
505
+ self._validate(value)
506
+ super().__setitem__(key, value)
507
+
508
+ def update(self, *args, **kwargs):
509
+ other = dict(*args, **kwargs)
510
+ for key, value in other.items():
511
+ self[key] = value # Triggers __setitem__
512
+
513
+ def setdefault(self, key, default=None):
514
+ if key not in self:
515
+ self[key] = default # Triggers __setitem__
516
+ return self[key]
517
+
445
518
  def header_check(record,headers,parse,hold=[]):
446
519
  """
447
520
  Check if a record is a header line and parse it accordingly.
@@ -3,7 +3,7 @@ requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
  [project]
5
5
  name = "pidibble"
6
- version = "1.3.2"
6
+ version = "1.4.0"
7
7
  authors = [
8
8
  { name="Cameron F Abrams", email="cfa22@drexel.edu" },
9
9
  ]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes