pidibble 1.5.2__tar.gz → 1.5.4__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 (60) hide show
  1. pidibble-1.5.4/.envrc +4 -0
  2. pidibble-1.5.4/.github/workflows/release.yaml +29 -0
  3. {pidibble-1.5.2 → pidibble-1.5.4}/.gitignore +3 -0
  4. pidibble-1.5.4/CHANGELOG.md +206 -0
  5. {pidibble-1.5.2 → pidibble-1.5.4}/PKG-INFO +5 -63
  6. {pidibble-1.5.2 → pidibble-1.5.4}/README.md +2 -62
  7. pidibble-1.5.4/docs/requirements.txt +8 -0
  8. pidibble-1.5.4/docs/source/changelog.md +5 -0
  9. pidibble-1.5.4/docs/source/changelog.rst +7 -0
  10. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/conf.py +2 -1
  11. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/index.rst +1 -0
  12. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/baseparsers.py +58 -57
  13. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/baserecord.py +34 -37
  14. pidibble-1.5.4/pidibble/hex.py +68 -0
  15. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/mmcif_parse.py +143 -143
  16. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/pdbparse.py +116 -108
  17. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/pdbrecord.py +291 -265
  18. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/resources/pdb_format.yaml +3 -3
  19. {pidibble-1.5.2 → pidibble-1.5.4}/pyproject.toml +4 -1
  20. pidibble-1.5.4/scripts/release.sh +88 -0
  21. pidibble-1.5.2/.github/workflows/release.yaml +0 -41
  22. pidibble-1.5.2/MANIFEST.in +0 -1
  23. pidibble-1.5.2/docs/requirements.txt +0 -15
  24. pidibble-1.5.2/pidibble/hex.py +0 -40
  25. pidibble-1.5.2/pidibble/resources/__init__.py +0 -6
  26. {pidibble-1.5.2 → pidibble-1.5.4}/.readthedocs.yaml +0 -0
  27. {pidibble-1.5.2 → pidibble-1.5.4}/LICENSE +0 -0
  28. {pidibble-1.5.2 → pidibble-1.5.4}/docs/Makefile +0 -0
  29. {pidibble-1.5.2 → pidibble-1.5.4}/docs/make.bat +0 -0
  30. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/_static/css/custom.css +0 -0
  31. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/API.rst +0 -0
  32. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.baseparsers.rst +0 -0
  33. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.baserecord.rst +0 -0
  34. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.hex.rst +0 -0
  35. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.mmcif_parse.rst +0 -0
  36. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.pdbparse.rst +0 -0
  37. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.pdbrecord.rst +0 -0
  38. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.resources.rst +0 -0
  39. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/api/pidibble.rst +0 -0
  40. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/installation.rst +0 -0
  41. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/notes.md +0 -0
  42. {pidibble-1.5.2 → pidibble-1.5.4}/docs/source/usage.rst +0 -0
  43. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/__init__.py +0 -0
  44. {pidibble-1.5.2 → pidibble-1.5.4}/pidibble/resources/mmcif_format.yaml +0 -0
  45. {pidibble-1.5.2 → pidibble-1.5.4}/tests/__init__.py +0 -0
  46. {pidibble-1.5.2 → pidibble-1.5.4}/tests/conftest.py +0 -0
  47. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_hex/my_system.pdb +0 -0
  48. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_hex.py +0 -0
  49. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/4tvp.cif +0 -0
  50. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/4tvp.pdb +0 -0
  51. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/4zmj-newresnames.pdb +0 -0
  52. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/4zmj.cif +0 -0
  53. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/4zmj.pdb +0 -0
  54. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/6m0j.pdb +0 -0
  55. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/8fae.cif +0 -0
  56. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/G.pdb +0 -0
  57. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/GG.pdb +0 -0
  58. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/test.pdb +0 -0
  59. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb/test_pdb_format.yaml +0 -0
  60. {pidibble-1.5.2 → pidibble-1.5.4}/tests/unit/test_rcsb.py +0 -0
pidibble-1.5.4/.envrc ADDED
@@ -0,0 +1,4 @@
1
+ # direnv: auto-activate this repo's uv-managed virtualenv on `cd` in.
2
+ # Created with `uv venv .venv`. Run `direnv allow` once to trust this file.
3
+ export VIRTUAL_ENV="$PWD/.venv"
4
+ PATH_add "$VIRTUAL_ENV/bin"
@@ -0,0 +1,29 @@
1
+ name: Release & Upload to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ release:
11
+ uses: cameronabrams/workflows/.github/workflows/python-release.yml@main
12
+ with:
13
+ rtd_slug: pidibble
14
+ run_tests: true
15
+ secrets: inherit
16
+
17
+ publish:
18
+ needs: release
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ id-token: write
22
+ steps:
23
+ - name: Download dist artifacts
24
+ uses: actions/download-artifact@v4
25
+ with:
26
+ name: dist
27
+ path: dist/
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -136,3 +136,6 @@ dmypy.json
136
136
  .pyre/
137
137
  .vscode/settings.json
138
138
 
139
+
140
+ # uv local lockfile (libraries: not committed)
141
+ uv.lock
@@ -0,0 +1,206 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [1.5.4] - 2026-07-14
9
+
10
+ ### Fixed
11
+ - ATOM/HETATM/ANISOU `charge` field retyped from `Float` to `String`. The PDB charge column (79–80) is a formatted string (e.g. `1-`, `2+`), never a plain float, so every populated charge previously failed `float()` and emitted a spurious "Could not parse field charge" warning while discarding the value. Charges are now captured correctly (e.g. `1-`).
12
+ - Off-by-one in `StringParser.report_record_error()` highlight: the error display dropped the character at the field's first column and coloured a window shifted one column to the right of the offending field. The highlight now wraps exactly the columns given by the field's byte range.
13
+
14
+ ## [1.5.3] - 2026-05-03
15
+
16
+ ### Fixed
17
+ - `PDBParser(PDBcode=...)` legacy parameter silently swallowed by `**kwargs`; restored via explicit mapping to `source_id`/`source_db='rcsb'`
18
+ - Eight bare `except:` clauses narrowed to specific exception types throughout
19
+ - Bitwise `&=` used as logical AND in `BaseRecord.empty()` replaced with `all()`
20
+ - `str2int_sig` raised `IndexError` on empty-string input; added guard before index access
21
+ - `!= None` / `== None` comparisons replaced with `is not None` / `is None` throughout
22
+ - `type(x) == T` identity comparisons replaced with `isinstance(x, T)` throughout
23
+ - `elif type(p) == list:` in `parse_tokens()` was unreachable; corrected to `isinstance(p, PDBRecordList)`
24
+ - Mutable default arguments `hold={}` and `hold=[]` in `gather_token` and `header_check` replaced with `None`
25
+
26
+ ### Changed
27
+ - Global hex-tripped flag in `hex.py` replaced with `AtomSerialParser` callable class; each `PDBParser` instance owns its own state, eliminating thread-safety hazard and cross-parse contamination
28
+ - `mappers` default argument changed from a mutable dict literal to `None`; default built inside `__init__`
29
+ - Resource YAML files now loaded via `importlib.resources.files()` instead of `os.path.dirname(resources.__file__)`, ensuring correct behavior inside wheels and zip archives
30
+ - `resources/__init__.py` removed; `resources/` is now a plain data directory, not a sub-package
31
+ - `MANIFEST.in` removed; hatchling auto-discovers package data from git-tracked files
32
+ - PEP 8 spacing applied throughout all source files
33
+ - `parse_embedded()` refactored: `triggered`/`capturing` boolean pair replaced with explicit `_EmbedState` enum (`SEARCHING`, `PRE_CAPTURE`, `CAPTURING`); setup phase extracted into `_setup_embed_context()`
34
+
35
+ ### Added
36
+ - `CHANGELOG.md` with full release history
37
+ - `scripts/release.sh` for automated version rotation, tagging, and push
38
+ - `[test]` optional dependency group in `pyproject.toml`
39
+
40
+ ---
41
+
42
+ ## [1.5.2] - 2025-09-16
43
+
44
+ ### Added
45
+ - Capability to download structures from OPM and split DUM residues into a separate PDB file
46
+
47
+ ## [1.5.1] - 2025-09-15
48
+
49
+ ### Fixed
50
+ - Minor fixes following 1.5.0
51
+
52
+ ## [1.5.0] - 2025-09-15
53
+
54
+ ### Added
55
+ - Initial OPM support
56
+
57
+ ## [1.4.2] - 2025-08-11
58
+
59
+ ### Changed
60
+ - Updated AlphaFold interface to current API
61
+
62
+ ## [1.4.1] - 2025-08-07
63
+
64
+ ### Fixed
65
+ - Parsing bug in `PDBRecordList`
66
+
67
+ ## [1.4.0] - 2025-07-29
68
+
69
+ ### Added
70
+ - `PDBRecordList` and `PDBRecordDict` classes
71
+
72
+ ## [1.3.3] - 2025-07-29
73
+
74
+ ### Fixed
75
+ - Bugs where missing records were incorrectly assumed present during mmCIF parsing
76
+
77
+ ## [1.3.2] - 2025-07-25
78
+
79
+ ### Added
80
+ - `filepath` parameter in `PDBParser()` for transparent reading of local files
81
+
82
+ ## [1.3.1] - 2025-07-25
83
+
84
+ ### Fixed
85
+ - Minor fixes following 1.3.0
86
+
87
+ ## [1.3.0] - 2025-07-16
88
+
89
+ ### Changed
90
+ - Streamlined class attribute usage throughout
91
+ - Full API documentation published
92
+
93
+ ## [1.2.3] - 2025-03-06
94
+
95
+ ### Fixed
96
+ - Negative residue sequence numbers now parsed correctly
97
+
98
+ ## [1.2.2] - 2025-03-04
99
+
100
+ ### Fixed
101
+ - Minor fixes following 1.2.1
102
+
103
+ ## [1.2.1] - 2024-10-01
104
+
105
+ ### Fixed
106
+ - Hexadecimal serial number parsing issues (again)
107
+
108
+ ## [1.2.0] - 2024-09-08
109
+
110
+ ### Fixed
111
+ - Hexadecimal serial number parsing issues
112
+
113
+ ## [1.1.9] - 2024-08-08
114
+
115
+ ### Fixed
116
+ - `nan` values and `*` filler characters in numeric fields now handled gracefully
117
+
118
+ ## [1.1.8] - 2024-07-15
119
+
120
+ ### Added
121
+ - Unstructured REMARK records (e.g. from PACKMOL output) parsed as `REMARK.-1`
122
+
123
+ ## [1.1.6] - 2024-07-11
124
+
125
+ ### Fixed
126
+ - Hexadecimal atom serial detection when no `a-f` characters are present, based on value exceeding 99999
127
+
128
+ ## [1.1.5] - 2024-07-11
129
+
130
+ ### Fixed
131
+ - Hex-or-integer detection now restricted to atom serial number fields only
132
+
133
+ ## [1.1.4] - 2024-07-11
134
+
135
+ ### Added
136
+ - Hexadecimal atom serial number support for files with more than 99999 atoms
137
+
138
+ ## [1.1.3] - 2024-03-21
139
+
140
+ ### Added
141
+ - Ability to group records into models for multi-model PDB entries
142
+
143
+ ## [1.1.2] - 2024-02-28
144
+
145
+ ### Added
146
+ - Ability to fetch structures from the AlphaFold database
147
+
148
+ ## [1.1.1] - 2023-09-19
149
+
150
+ ### Added
151
+ - Version detection via `importlib.metadata`
152
+
153
+ ## [1.0.9.1] - 2023-08-28
154
+
155
+ ### Added
156
+ - Limited mmCIF parsing: `ATOM`, `HETATM`, `SSBOND`, `LINK`, `SEQADV`, `REMARK 350`, and `REMARK 465` records
157
+
158
+ ## [1.0.8] - 2023-08-23
159
+
160
+ ### Fixed
161
+ - Variations in how symmetry operation matrices are represented in PDB files
162
+
163
+ ## [1.0.7.7] - 2023-08-22
164
+
165
+ ### Changed
166
+ - Cleaned up logging throughout
167
+
168
+ ## [1.0.7.6] - 2023-08-22
169
+
170
+ ### Fixed
171
+ - Leading whitespace in `resName` field of `Residue10` record sometimes ignored
172
+
173
+ ## [1.0.7.5] - 2023-08-18
174
+
175
+ ### Added
176
+ - Support for four-letter residue names
177
+
178
+ ## [1.0.7.4] - 2023-08-04
179
+
180
+ ### Added
181
+ - Logging functionality
182
+
183
+ ## [1.0.7.3] - 2023-08-03
184
+
185
+ ### Changed
186
+ - Improved parsing of BIOMT transforms
187
+
188
+ ## [1.0.7.2] - 2023-08-03
189
+
190
+ ### Added
191
+ - Documentation stub on ReadTheDocs
192
+
193
+ ## [1.0.7.1] - 2023-08-03
194
+
195
+ ### Added
196
+ - Support for split BIOMT tables and REMARK 280, 375, 650, and 700
197
+
198
+ ## [1.0.7] - 2023-08-01
199
+
200
+ ### Added
201
+ - Pretty-print support for parsed records
202
+
203
+ ## [1.0] - 2023-07-01
204
+
205
+ ### Added
206
+ - Initial release
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pidibble
3
- Version: 1.5.2
3
+ Version: 1.5.4
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/
@@ -14,6 +14,8 @@ Requires-Python: >=3.7
14
14
  Requires-Dist: mmcif
15
15
  Requires-Dist: numpy>=1.24
16
16
  Requires-Dist: pyyaml>=6
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest; extra == 'test'
17
19
  Description-Content-Type: text/markdown
18
20
 
19
21
  # Pidibble
@@ -90,66 +92,6 @@ ATOM
90
92
 
91
93
  ```
92
94
 
93
- ## Release History
94
- * 1.5.2
95
- * added capability to download from OPM and split out DUM resi's into a "dum" pdb
96
- * 1.4.2
97
- * updated alphafold interface
98
- * 1.4.1
99
- * Fixed parsing bug in `PDBRecordList`
100
- * 1.4.0
101
- * Introduced `PDBRecordList` and `PDBRecordDict` classes
102
- * 1.3.3
103
- * fixed bugs regarding assuming missing records actually present in mmcif parsing
104
- * 1.3.2
105
- * implemented `filepath` parameter in `PDBParser()` to make
106
- reading local files more transparent
107
- * 1.3.0
108
- * streamline class attribute usage; full API documentation
109
- * 1.2.3:
110
- * bugfix: negative resids allowed
111
- * 1.2.1:
112
- * bugfix: hex issues AGAIN
113
- * 1.2.0
114
- * bugfix: hex issues again
115
- * 1.1.9
116
- * gently handles any nan values or '*' fillers
117
- * 1.1.8
118
- * Allow unstructured REMARK records (thanks a lot, packmol) to be parsed as REMARK.-1
119
- * 1.1.6
120
- * bugfix: detection of hex when no abcdef present based on a trip
121
- * 1.1.5
122
- * bugfix: allow for ONLY atom serial numbers to be hex-or-int
123
- * 1.1.4
124
- * Added ability to read hexadecimal atom indices for files with > 99999 atoms
125
- * 1.1.3
126
- * Added ability to group into models for multiple-model entries
127
- * 1.1.2
128
- * Added ability to retrieve pdbs from AlphaFold database
129
- * 1.1.1
130
- * version detection
131
- * 1.0.9.1
132
- * added limited functionality to parse mmCIF files, in particular to generate any
133
- ATOM, HETATM, SSBOND, LINK, SEQADV, REMARK 350, and REMARK 465 records
134
- * 1.0.8
135
- * bug fix: handle variations in how symmetry operation matrices are represented
136
- * 1.0.7.7
137
- * cleaned up logging
138
- * 1.0.7.6
139
- * bug fix: leading whitespace in resname field of Residue10 record sometimes ignored
140
- * 1.0.7.5
141
- * support for four-letter residue names
142
- * 1.0.7.4
143
- * added logging functionality
144
- * 1.0.7.3
145
- * improved parsing of BIOMT transforms
146
- * 1.0.7.2
147
- * added documentation stub at readthedocs
148
- * 1.0.7.1
149
- * support for split BIOMT tables and REMARKS 280, 375, 650, and 700
150
- * 1.0.7
151
- * pretty-print enabled
152
- * 1.0
153
- * Initial version
154
-
95
+ ## Changelog
155
96
 
97
+ See [CHANGELOG.md](CHANGELOG.md) for the full release history.
@@ -72,66 +72,6 @@ ATOM
72
72
 
73
73
  ```
74
74
 
75
- ## Release History
76
- * 1.5.2
77
- * added capability to download from OPM and split out DUM resi's into a "dum" pdb
78
- * 1.4.2
79
- * updated alphafold interface
80
- * 1.4.1
81
- * Fixed parsing bug in `PDBRecordList`
82
- * 1.4.0
83
- * Introduced `PDBRecordList` and `PDBRecordDict` classes
84
- * 1.3.3
85
- * fixed bugs regarding assuming missing records actually present in mmcif parsing
86
- * 1.3.2
87
- * implemented `filepath` parameter in `PDBParser()` to make
88
- reading local files more transparent
89
- * 1.3.0
90
- * streamline class attribute usage; full API documentation
91
- * 1.2.3:
92
- * bugfix: negative resids allowed
93
- * 1.2.1:
94
- * bugfix: hex issues AGAIN
95
- * 1.2.0
96
- * bugfix: hex issues again
97
- * 1.1.9
98
- * gently handles any nan values or '*' fillers
99
- * 1.1.8
100
- * Allow unstructured REMARK records (thanks a lot, packmol) to be parsed as REMARK.-1
101
- * 1.1.6
102
- * bugfix: detection of hex when no abcdef present based on a trip
103
- * 1.1.5
104
- * bugfix: allow for ONLY atom serial numbers to be hex-or-int
105
- * 1.1.4
106
- * Added ability to read hexadecimal atom indices for files with > 99999 atoms
107
- * 1.1.3
108
- * Added ability to group into models for multiple-model entries
109
- * 1.1.2
110
- * Added ability to retrieve pdbs from AlphaFold database
111
- * 1.1.1
112
- * version detection
113
- * 1.0.9.1
114
- * added limited functionality to parse mmCIF files, in particular to generate any
115
- ATOM, HETATM, SSBOND, LINK, SEQADV, REMARK 350, and REMARK 465 records
116
- * 1.0.8
117
- * bug fix: handle variations in how symmetry operation matrices are represented
118
- * 1.0.7.7
119
- * cleaned up logging
120
- * 1.0.7.6
121
- * bug fix: leading whitespace in resname field of Residue10 record sometimes ignored
122
- * 1.0.7.5
123
- * support for four-letter residue names
124
- * 1.0.7.4
125
- * added logging functionality
126
- * 1.0.7.3
127
- * improved parsing of BIOMT transforms
128
- * 1.0.7.2
129
- * added documentation stub at readthedocs
130
- * 1.0.7.1
131
- * support for split BIOMT tables and REMARKS 280, 375, 650, and 700
132
- * 1.0.7
133
- * pretty-print enabled
134
- * 1.0
135
- * Initial version
136
-
75
+ ## Changelog
137
76
 
77
+ See [CHANGELOG.md](CHANGELOG.md) for the full release history.
@@ -0,0 +1,8 @@
1
+ sphinx
2
+ furo
3
+ sphinx-copybutton
4
+ sphinxcontrib-mermaid
5
+ myst-parser
6
+ readthedocs-sphinx-ext
7
+ pyyaml
8
+ pidibble
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ```{include} ../../CHANGELOG.md
4
+ :heading-offset: 1
5
+ ```
@@ -0,0 +1,7 @@
1
+ .. _changelog:
2
+
3
+ Changelog
4
+ =========
5
+
6
+ .. include:: ../../CHANGELOG.md
7
+ :parser: myst_parser.sphinx_
@@ -22,6 +22,7 @@ extensions = [
22
22
  'sphinxcontrib.mermaid',
23
23
  'sphinx.ext.napoleon',
24
24
  'sphinx.ext.viewcode',
25
+ 'myst_parser',
25
26
  ]
26
27
 
27
28
  autosummary_generate = True # Enable autosummary tables
@@ -49,7 +50,7 @@ html_theme_options = {
49
50
  "footer_icons": [
50
51
  {
51
52
  "name": "GitHub",
52
- "url": "https://github.com/cameronabrams/ycleptic",
53
+ "url": "https://github.com/cameronabrams/pidibble",
53
54
  "html": """
54
55
  <svg role="img" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
55
56
  <title>GitHub</title>
@@ -30,3 +30,4 @@ Contents
30
30
  installation
31
31
  usage
32
32
  API <api/API>
33
+ changelog
@@ -7,21 +7,21 @@
7
7
 
8
8
  """
9
9
  import logging
10
- logger=logging.getLogger(__name__)
10
+ logger = logging.getLogger(__name__)
11
11
 
12
12
  class ListParser:
13
13
  """
14
14
  A simple parser for lists of strings, with a customizable delimiter.
15
15
  """
16
16
 
17
- def __init__(self,d=','):
18
- self.d=d
19
-
20
- def parse(self,string):
17
+ def __init__(self, d=','):
18
+ self.d = d
19
+
20
+ def parse(self, string):
21
21
  """
22
22
  Parse a string into a list of strings, using the specified delimiter.
23
23
  If no delimiter is specified, it splits on whitespace.
24
-
24
+
25
25
  Parameters
26
26
  ----------
27
27
  string : str
@@ -32,12 +32,12 @@ class ListParser:
32
32
  list
33
33
  A list of strings parsed from the input string.
34
34
  """
35
- if self.d==None:
36
- return [x for x in string.split() if x.strip()!='']
35
+ if self.d is None:
36
+ return [x for x in string.split() if x.strip() != '']
37
37
  else:
38
- return [x.strip() for x in string.split(self.d) if x.strip()!='']
39
-
40
- def list_parse(obj,d):
38
+ return [x.strip() for x in string.split(self.d) if x.strip() != '']
39
+
40
+ def list_parse(obj, d):
41
41
  """
42
42
  A factory function to create a ListParser with a specific delimiter.
43
43
 
@@ -58,21 +58,21 @@ def list_parse(obj,d):
58
58
  """
59
59
  Define a dictionary of parsers for different list formats
60
60
  """
61
- ListParsers={
62
- 'CList':list_parse(ListParser,','),
63
- 'SList':list_parse(ListParser,';'),
64
- 'WList':list_parse(ListParser,None),
65
- 'DList':list_parse(ListParser,':'),
66
- 'LList':list_parse(ListParser,'\n')
61
+ ListParsers = {
62
+ 'CList': list_parse(ListParser, ','),
63
+ 'SList': list_parse(ListParser, ';'),
64
+ 'WList': list_parse(ListParser, None),
65
+ 'DList': list_parse(ListParser, ':'),
66
+ 'LList': list_parse(ListParser, '\n')
67
67
  }
68
68
 
69
- _cols="""
69
+ _cols = """
70
70
  1 2 3 4 5 6 7 8
71
71
  12345678901234567890123456789012345678901234567890123456789012345678901234567890"""
72
72
  class StringParser:
73
73
  """
74
74
  A parser for fixed-width strings, with a customizable field map.
75
-
75
+
76
76
  Parameters
77
77
  ----------
78
78
  fmtdict : dict
@@ -82,15 +82,15 @@ class StringParser:
82
82
  allowed : dict, optional
83
83
  A dictionary mapping field values to allowed values, for validation.
84
84
  """
85
- def __init__(self,fmtdict,typemap,allowed={}):
86
- self.typemap=typemap
87
- self.fields={k:v for k,v in fmtdict.items()}
88
- self.allowed=allowed
85
+ def __init__(self, fmtdict, typemap, allowed={}):
86
+ self.typemap = typemap
87
+ self.fields = {k: v for k, v in fmtdict.items()}
88
+ self.allowed = allowed
89
89
 
90
90
  def parse(self, record):
91
91
  """
92
92
  Parse a fixed-width string record into a dictionary of fields.
93
-
93
+
94
94
  Parameters
95
95
  ----------
96
96
  record : str
@@ -101,39 +101,39 @@ class StringParser:
101
101
  dict
102
102
  A dictionary of fields parsed from the input record.
103
103
  """
104
- if len(record)>80:
104
+ if len(record) > 80:
105
105
  logger.warning('The following record exceeds 80 bytes in length:')
106
106
  self.report_record_error(record)
107
107
  logger.warning('Stripping...')
108
108
  record = record.strip()
109
- if len(record)>80:
110
- raise ValueError(f'Record is too long; something wrong with your PDB file?')
111
- input_dict={}
112
- record+=' '*(80-len(record)) # pad
113
- for k,v in self.fields.items():
114
- typestring,byte_range=v
115
- typ=self.typemap[typestring]
116
- assert byte_range[1]<=len(record),f'{record} {byte_range}'
109
+ if len(record) > 80:
110
+ raise ValueError(f'Record is too long; something wrong with your PDB file?')
111
+ input_dict = {}
112
+ record += ' ' * (80 - len(record)) # pad
113
+ for k, v in self.fields.items():
114
+ typestring, byte_range = v
115
+ typ = self.typemap[typestring]
116
+ assert byte_range[1] <= len(record), f'{record} {byte_range}'
117
117
  # using columns beginning with "1" not "0"
118
- fieldstring=record[byte_range[0]-1:byte_range[1]]
119
- fieldstring=fieldstring.rstrip()
118
+ fieldstring = record[byte_range[0] - 1:byte_range[1]]
119
+ fieldstring = fieldstring.rstrip()
120
120
  try:
121
121
  # if len(fieldstring)>0 and not typ==str:
122
122
  # fieldstring=''
123
- input_dict[k]='' if fieldstring=='' else typ(fieldstring)
124
- except:
125
- self.report_field_error(record,k)
126
- input_dict[k]=''
127
- if typ==str:
128
- input_dict[k]=input_dict[k].strip()
123
+ input_dict[k] = '' if fieldstring == '' else typ(fieldstring)
124
+ except (ValueError, TypeError):
125
+ self.report_field_error(record, k)
126
+ input_dict[k] = ''
127
+ if typ == str:
128
+ input_dict[k] = input_dict[k].strip()
129
129
  if fieldstring in self.allowed:
130
- assert input_dict[k] in self.allowed[fieldstring],f'Value {input_dict[k]} is not allowed for field {k}; allowed values are {self.allowed[fieldstring]}'
130
+ assert input_dict[k] in self.allowed[fieldstring], f'Value {input_dict[k]} is not allowed for field {k}; allowed values are {self.allowed[fieldstring]}'
131
131
  return input_dict
132
-
133
- def report_record_error(self,record,byte_range=[]):
132
+
133
+ def report_record_error(self, record, byte_range=[]):
134
134
  """
135
135
  Report an error in parsing a fixed-width string record.
136
-
136
+
137
137
  Parameters
138
138
  ----------
139
139
  record : str
@@ -143,14 +143,14 @@ class StringParser:
143
143
  If empty, the entire record is reported.
144
144
  """
145
145
  if byte_range:
146
- record=record[:byte_range[0]-1]+'\033[91m'+record[byte_range[0]:byte_range[1]+1]+'\033[0m'+record[byte_range[1]+1:]
147
- repstr=_cols+'\n'+record+'|'
146
+ record = record[:byte_range[0] - 1] + '\033[91m' + record[byte_range[0] - 1:byte_range[1]] + '\033[0m' + record[byte_range[1]:]
147
+ repstr = _cols + '\n' + record + '|'
148
148
  logger.warning(repstr)
149
-
150
- def report_field_error(self,record,k):
149
+
150
+ def report_field_error(self, record, k):
151
151
  """
152
152
  Report an error in parsing a specific field from a fixed-width string record.
153
-
153
+
154
154
  Parameters
155
155
  ----------
156
156
  record : str
@@ -158,26 +158,27 @@ class StringParser:
158
158
  k : str
159
159
  The field name that caused the error.
160
160
  """
161
- byte_range=self.fields[k][1]
161
+ byte_range = self.fields[k][1]
162
162
  logger.warning(f'Could not parse field {k} from bytes {byte_range}:')
163
- self.report_record_error(record,byte_range=byte_range)
163
+ self.report_record_error(record, byte_range=byte_range)
164
164
 
165
165
  def safe_float(x):
166
166
  """
167
167
  Convert a string to a float, returning 0.0 if the string is 'nan'.
168
168
  """
169
- if x=='nan':
169
+ if x == 'nan':
170
170
  return 0.0
171
171
  return float(x)
172
172
 
173
- def str2int_sig(arg:str):
173
+ def str2int_sig(arg: str):
174
174
  """
175
175
  Convert a string to an integer, returning -1 if the string is not numeric.
176
176
  If the string starts with a '-', it is returned as an integer.
177
177
  """
178
- if not arg.strip().isnumeric():
179
- if arg.strip()[0]=='-':
178
+ stripped = arg.strip()
179
+ if not stripped.isnumeric():
180
+ if stripped and stripped[0] == '-':
180
181
  return int(arg)
181
182
  else:
182
183
  return -1
183
- return int(arg)
184
+ return int(arg)