forked from haddocking/pdb-tools
-
Notifications
You must be signed in to change notification settings - Fork 1
/
pdb_reres.py
executable file
·153 lines (120 loc) · 4.58 KB
/
pdb_reres.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
"""
Renumbers residues in a PDB file.
usage: python pdb_reres.py <pdb file> [-chain <ids>][-resid <int>]
example:
python pdb_reres.py 1CTF.pdb -resid 1 # renumbers from 1, sequentially
python pdb_reres.py 1CTF.pdb -chain -resid 1 # renumbers each chain from 1
python pdb_reres.py 1CTF.pdb -chain A -resid 1 # renumbers chain A from 1
Author: {0} ({1})
This program is part of the PDB tools distributed with HADDOCK
or with the HADDOCK tutorial. The utilities in this package
can be used to quickly manipulate PDB files, with the benefit
of 'piping' several different commands. This is a rewrite of old
FORTRAN77 code that was taking too much effort to compile. RIP.
"""
import os
import re
import sys
__author__ = "Joao Rodrigues"
__email__ = "[email protected]"
USAGE = __doc__.format(__author__, __email__)
def check_input(arg_list):
"""
Checks whether to read from stdin/file and validates user input/options.
"""
# Dictionary to define options and default values,
# rules to validate input values, and handlers to parse them if needed.
# @joaomcteixeira
user_opts = {'resid': 1, 'chain': None} # defaults if no opt is called
opts_defaults = {'resid': 1, 'chain': {}} # default if opt *is* called
rules = {'resid': re.compile('[\-0-9]+'), # option with numeric value
'chain': re.compile('[A-Za-z0-9,]+'), # options with alpha value
}
handlers = {'resid': lambda x: int(x),
'chain': lambda x: set(x.split(','))}
pdbfh = None
# First argument is always file name
# If it is an option (or no args), assume reading from input stream
if not arg_list or arg_list[0][0] == '-':
if not sys.stdin.isatty():
pdbfh = sys.stdin
else:
sys.stderr.write(USAGE)
sys.exit(1)
else:
if not sys.stdin.isatty():
sys.stderr.write('Error: multiple sources of input' + '\n')
sys.exit(1)
pdbfh = open(arg_list[0])
arg_list = arg_list[1:]
# Check for any combination of arguments
n_args, skip = len(arg_list), False
for idx, arg in enumerate(arg_list):
if skip:
skip = False
continue
# Option
if re.match('\-', arg):
name = arg[1:]
# Validate option name
if name not in rules:
sys.stderr.write('Unrecognized option: ' + arg + '\n')
sys.exit(1)
rule = rules[name]
# Validate option value (if any)
if idx + 1 < n_args and arg_list[idx + 1][0] != '-':
raw_val = arg_list[idx + 1]
val = rule.match(raw_val)
if val:
user_opts[name] = handlers[name](val.group(0))
skip = True
else:
sys.stderr.write('Bad value for \'' + arg + '\': '
+ raw_val +'\n')
sys.exit(1)
else: # no-value option or last option
user_opts[name] = opts_defaults[name]
else:
sys.stderr.write('Unrecognized option: ' + arg + '\n')
sys.exit(1)
return (pdbfh, user_opts)
def _renumber_pdb_residue(fhandle, opt_dict):
"""Keeping code organized ..."""
opts = opt_dict
resi = opts['resid'] - 1
# if chain is none, renumber everyone
# if chain is not none but empty, restart at each chain
# otherwise, renumber only chain
on_chain = opts.get('chain') is not None
prev_chain, prev_resi = None, None
for line in fhandle:
if line.startswith(('ATOM', 'HETATM', 'TER')):
if line[21] != prev_chain:
if on_chain:
resi = opts['resid'] - 1
prev_chain = line[21]
if line[22:27] != prev_resi:
prev_resi = line[22:27]
resi += 1
if not opts.get('chain') or line[21] in opts['chain']:
yield line[:22] + str(resi).rjust(4) + line[27:]
continue
yield line
if __name__ == '__main__':
# Check Input
pdbfh, options = check_input(sys.argv[1:])
# Do the job
new_pdb = _renumber_pdb_residue(pdbfh, options)
try:
sys.stdout.write(''.join(new_pdb))
sys.stdout.flush()
except IOError:
# This is here to catch Broken Pipes
# for example to use 'head' or 'tail' without
# the error message showing up
pass
# last line of the script
# We can close it even if it is sys.stdin
pdbfh.close()
sys.exit(0)