Merge pull request #187 from speleo3/remove-unused

Remove unused code
This commit is contained in:
Thomas Holder
2024-02-19 08:39:07 +01:00
committed by GitHub
12 changed files with 76 additions and 418 deletions

View File

@@ -2,6 +2,17 @@
Changelog Changelog
********* *********
Upcoming release (TBD)
======================
Changes
-------
* Removed the following unused command line options: ``-t``, ``--thermophile``,
``-a``, ``--alignment``, ``-m``, ``--mutation``, ``--mutator``,
``--mutator-option``
* Removed several unused API functions
Current Current
======= =======

View File

@@ -10,9 +10,9 @@ PROPKA predicts the pKa values of ionizable groups in proteins and
protein-ligand complexes based in the 3D structure. The protein-ligand complexes based in the 3D structure. The
:program:`propka3` command has the following options:: :program:`propka3` command has the following options::
propka3 [-h] [-f FILENAMES] [-r REFERENCE] [-c CHAINS] [-i TITRATE_ONLY] [-t THERMOPHILES] [-a ALIGNMENT] [-m MUTATIONS] propka3 [-h] [-f FILENAMES] [-r REFERENCE] [-c CHAINS] [-i TITRATE_ONLY]
[-v VERSION_LABEL] [-p PARAMETERS] [--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-o PH] [-w WINDOW WINDOW WINDOW] [-v VERSION_LABEL] [-p PARAMETERS] [--log-level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [-o PH] [-w WINDOW WINDOW WINDOW]
[-g GRID GRID GRID] [--mutator MUTATOR] [--mutator-option MUTATOR_OPTIONS] [-d] [-l] [-k] [-q] [--protonate-all] [-g GRID GRID GRID] [-d] [-l] [-k] [-q] [--protonate-all]
input_pdb input_pdb
@@ -47,21 +47,6 @@ protein-ligand complexes based in the 3D structure. The
should be a comma-separated list of "chain:resnum" should be a comma-separated list of "chain:resnum"
values; for example: ``-i "A:10,A:11"`` (default: None) values; for example: ``-i "A:10,A:11"`` (default: None)
.. option:: -t THERMOPHILES, --thermophile THERMOPHILES
defining a thermophile filename; usually used in
'alignment-mutations' (default: None)
.. option:: -a ALIGNMENT, --alignment ALIGNMENT
alignment file connecting <filename> and <thermophile>
[<thermophile>.pir] (default: None)
.. option:: -m MUTATIONS, --mutation MUTATIONS
specifying mutation labels which is used to modify
<filename> according to, e.g. N25R/N181D (default: None)
.. option:: --version .. option:: --version
show program's version number and exit show program's version number and exit
@@ -90,16 +75,6 @@ protein-ligand complexes based in the 3D structure. The
setting the pH-grid to calculate e.g. stability related setting the pH-grid to calculate e.g. stability related
properties (default: (0.0, 14.0, 0.1)) properties (default: (0.0, 14.0, 0.1))
.. option:: --mutator MUTATOR
setting approach for mutating <filename>
[alignment/scwrl/jackal] (default: None)
.. option:: --mutator-option MUTATOR_OPTIONS
setting property for mutator [e.g. type="side-chain"]
(default: None)
.. option:: -d, --display-coupled-residues .. option:: -d, --display-coupled-residues
Displays alternative pKa values due to coupling of Displays alternative pKa values due to coupling of

View File

@@ -7,8 +7,7 @@ The :class:`Atom` class contains all atom information found in the PDB file.
""" """
import string import string
from typing import cast, List, NoReturn, Optional, TYPE_CHECKING from typing import List, Optional, TYPE_CHECKING
import warnings
from propka.lib import make_tidy_atom_label from propka.lib import make_tidy_atom_label
from . import hybrid36 from . import hybrid36
@@ -46,7 +45,6 @@ class Atom:
group: Optional["Group"] = None group: Optional["Group"] = None
group_type: Optional[str] = None group_type: Optional[str] = None
cysteine_bridge: bool = False cysteine_bridge: bool = False
residue: NoReturn = None # type: ignore[assignment]
conformation_container: Optional["ConformationContainer"] = None conformation_container: Optional["ConformationContainer"] = None
molecular_container: Optional["MolecularContainer"] = None molecular_container: Optional["MolecularContainer"] = None
is_protonated: bool = False is_protonated: bool = False
@@ -87,7 +85,6 @@ class Atom:
Args: Args:
line: Line from a PDB file to set properties of atom. line: Line from a PDB file to set properties of atom.
""" """
self.number_of_bonded_elements: NoReturn = cast(NoReturn, {}) # FIXME unused?
self.bonded_atoms: List[Atom] = [] self.bonded_atoms: List[Atom] = []
self.set_properties(line) self.set_properties(line)
fmt = "{r.name:3s}{r.res_num:>4d}{r.chain_id:>2s}" fmt = "{r.name:3s}{r.res_num:>4d}{r.chain_id:>2s}"
@@ -302,45 +299,6 @@ class Atom:
atom_label=make_tidy_atom_label(self.name, self.element)) atom_label=make_tidy_atom_label(self.name, self.element))
return str_ return str_
def make_pdb_line2(self, numb=None, name=None, res_name=None, chain_id=None,
res_num=None, x=None, y=None, z=None, occ=None,
beta=None):
"""Create a PDB line.
TODO - this could/should be a @property method/attribute
TODO - figure out difference between make_pdb_line, and make_pdb_line2
Returns:
String with PDB line.
"""
warnings.warn("only used by unused function")
if numb is None:
numb = self.numb
if name is None:
name = self.name
if res_name is None:
res_name = self.res_name
if chain_id is None:
chain_id = self.chain_id
if res_num is None:
res_num = self.res_num
if x is None:
x = self.x
if y is None:
y = self.y
if z is None:
z = self.z
if occ is None:
occ = self.occ
if beta is None:
beta = self.beta
str_ = PDB_LINE_FMT2.format(
numb=numb, res_name=res_name, chain_id=chain_id, res_num=res_num,
x=x, y=y, z=z, occ=occ, beta=beta,
atom_label=make_tidy_atom_label(name, self.element)
)
return str_
def get_tidy_label(self): def get_tidy_label(self):
"""Returns a 'tidier' atom label for printing the new pdbfile """Returns a 'tidier' atom label for printing the new pdbfile
@@ -353,13 +311,3 @@ class Atom:
def __str__(self): def __str__(self):
"""Return an undefined-format string version of this atom.""" """Return an undefined-format string version of this atom."""
return STR_FMT.format(r=self) return STR_FMT.format(r=self)
def set_residue(self, residue: NoReturn):
""" Makes a reference to the parent residue
Args:
residue: the parent residue
"""
raise NotImplementedError("unused")
if self.residue is None:
self.residue = residue

View File

@@ -87,63 +87,6 @@ class BondMaker:
self.backbone_atoms = list(self.intra_residue_backbone_bonds.keys()) self.backbone_atoms = list(self.intra_residue_backbone_bonds.keys())
self.terminal_oxygen_names = ['OXT', 'O\'\''] self.terminal_oxygen_names = ['OXT', 'O\'\'']
def find_bonds_for_protein(self, protein):
"""Bonds proteins based on the way atoms normally bond.
Args:
protein: the protein to search for bonds
"""
raise NotImplementedError("unused")
_LOGGER.info('++++ Side chains ++++')
# side chains
for chain in protein.chains:
for residue in chain.residues:
if residue.res_name.replace(' ', '') not in ['N+', 'C-']:
self.find_bonds_for_side_chain(residue.atoms)
_LOGGER.info('++++ Backbones ++++')
# backbone
last_residues = []
for chain in protein.chains:
for i in range(1, len(chain.residues)):
if (chain.residues[i-1].res_name.replace(' ', '')
not in ['N+', 'C-']):
if (chain.residues[i].res_name.replace(' ', '')
not in ['N+', 'C-']):
self.connect_backbone(chain.residues[i-1],
chain.residues[i])
last_residues.append(chain.residues[i])
_LOGGER.info('++++ terminal oxygen ++++')
# terminal OXT
for last_residue in last_residues:
self.find_bonds_for_terminal_oxygen(last_residue)
_LOGGER.info('++++ cysteines ++++')
# Cysteines
for chain in protein.chains:
for i in range(0, len(chain.residues)):
if chain.residues[i].res_name == 'CYS':
for j in range(0, len(chain.residues)):
if chain.residues[j].res_name == 'CYS' and j != i:
self.check_for_cysteine_bonds(chain.residues[i],
chain.residues[j])
def check_for_cysteine_bonds(self, cys1, cys2):
"""Looks for potential bonds between two cysteines.
Args:
cys1: one of the cysteines to check
cys1: one of the cysteines to check
"""
raise NotImplementedError("unused")
for atom1 in cys1.atoms:
if atom1.name == 'SG':
for atom2 in cys2.atoms:
if atom2.name == 'SG':
dist = propka.calculations.squared_distance(atom1,
atom2)
# TODO - is SS_dist_squared an attribute of this class?
if dist < self.SS_dist_squared:
self.make_bond(atom1, atom2)
def find_bonds_for_terminal_oxygen(self, residue): def find_bonds_for_terminal_oxygen(self, residue):
"""Look for bonds for terminal oxygen. """Look for bonds for terminal oxygen.
@@ -423,34 +366,3 @@ class BondMaker:
atom2.bonded_atoms.append(atom1) atom2.bonded_atoms.append(atom1)
if atom2 not in atom1.bonded_atoms: if atom2 not in atom1.bonded_atoms:
atom1.bonded_atoms.append(atom2) atom1.bonded_atoms.append(atom2)
def generate_protein_bond_dictionary(self, atoms):
"""Generate dictionary of protein bonds.
Args:
atoms: list of atoms for bonding
"""
for atom in atoms:
for bonded_atom in atom.bonded_atoms:
resi_i = atom.res_name
name_i = atom.name
resi_j = bonded_atom.res_name
name_j = bonded_atom.name
if name_i not in (
self.backbone_atoms
or name_j not in self.backbone_atoms):
if name_i not in (
self.terminal_oxygen_names
and name_j not in self.terminal_oxygen_names):
if resi_i not in list(self.protein_bonds.keys()):
self.protein_bonds[resi_i] = {}
if name_i not in self.protein_bonds[resi_i]:
self.protein_bonds[resi_i][name_i] = []
if name_j not in self.protein_bonds[resi_i][name_i]:
self.protein_bonds[resi_i][name_i].append(name_j)
if resi_j not in list(self.protein_bonds.keys()):
self.protein_bonds[resi_j] = {}
if name_j not in self.protein_bonds[resi_j]:
self.protein_bonds[resi_j][name_j] = []
if name_i not in self.protein_bonds[resi_j][name_j]:
self.protein_bonds[resi_j][name_j].append(name_i)

View File

@@ -6,7 +6,7 @@ Container data structure for molecular conformations.
""" """
import logging import logging
import functools import functools
from typing import Callable, Dict, Iterable, Iterator, List, NoReturn, Optional, TYPE_CHECKING, Set from typing import Callable, Dict, Iterable, Iterator, List, Optional, TYPE_CHECKING, Set
from propka.lib import Options from propka.lib import Options
from propka.version import Version from propka.version import Version
@@ -497,18 +497,6 @@ class ConformationContainer:
group for group in self.groups group for group in self.groups
if group.residue_type in self.parameters.ions.keys()] if group.residue_type in self.parameters.ions.keys()]
def get_group_names(self, group_list: NoReturn) -> NoReturn: # FIXME unused?
"""Get names of groups in list.
Args:
group_list: list to check
Returns:
list of groups
"""
if TYPE_CHECKING:
assert False
return [group for group in self.groups if group.type in group_list]
def get_ligand_atoms(self) -> List["Atom"]: def get_ligand_atoms(self) -> List["Atom"]:
"""Get atoms associated with ligands. """Get atoms associated with ligands.

View File

@@ -11,7 +11,7 @@ Routines and classes for storing groups important to PROPKA calculations.
""" """
import logging import logging
import math import math
from typing import cast, Dict, Iterable, List, NoReturn, Optional from typing import Dict, List, Optional
import propka.ligand import propka.ligand
from propka.parameters import Parameters from propka.parameters import Parameters
@@ -119,8 +119,6 @@ class Group:
fmt = "{type:<3s}{name:>4s}{chain:>2s}" fmt = "{type:<3s}{name:>4s}{chain:>2s}"
self.label = fmt.format( self.label = fmt.format(
type=self.residue_type, name=atom.name, chain=atom.chain_id) type=self.residue_type, name=atom.name, chain=atom.chain_id)
# container for squared distances
self.squared_distances: NoReturn = cast(NoReturn, {}) # FIXME unused?
def couple_covalently(self, other: "Group") -> None: def couple_covalently(self, other: "Group") -> None:
"""Couple this group with another group. """Couple this group with another group.
@@ -162,46 +160,6 @@ class Group:
""" """
return self.non_covalently_coupled_groups return self.non_covalently_coupled_groups
def share_determinants(self, others: Iterable["Group"]) -> None:
"""Share determinants between this group and others.
Args:
others: list of other groups
"""
raise NotImplementedError("unused")
# for each determinant type
for other in others:
if other == self:
the_other = other
continue
for type_ in ['sidechain', 'backbone', 'coulomb']:
for det in other.determinants[type_]:
self.share_determinant(det, type_)
# recalculate pka values
self.calculate_total_pka()
the_other.calculate_total_pka()
def share_determinant(self, new_determinant: Determinant, type_: str) -> None:
"""Add determinant to this group's list of determinants.
Args:
new_determinant: determinant to add
type_: type of determinant
"""
added = False
# first check if we already have a determinant with this label
for own_determinant in self.determinants[type_]:
if own_determinant.group == new_determinant.group:
# if so, find the average value
avr = 0.5*(own_determinant.value + new_determinant.value)
own_determinant.value = avr
new_determinant.value = avr
added = True
# otherwise we just add the determinant to our list
if not added:
self.determinants[type_].append(
Determinant(new_determinant.group, new_determinant.value))
def __eq__(self, other): def __eq__(self, other):
"""Needed for creating sets of groups.""" """Needed for creating sets of groups."""
if self.atom.type == 'atom': if self.atom.type == 'atom':

View File

@@ -202,7 +202,7 @@ def add_iterative_ion_pair(object1: "Iterative", object2: "Iterative",
object2.determinants['sidechain'].append(interaction) object2.determinants['sidechain'].append(interaction)
def add_determinants(iterative_interactions: List[Interaction], version: Version, _=None): def add_determinants(iterative_interactions: List[Interaction], version: Version):
"""Add determinants iteratively. """Add determinants iteratively.
The iterative pKa scheme. Later it is all added in 'calculateTotalPKA' The iterative pKa scheme. Later it is all added in 'calculateTotalPKA'

View File

@@ -8,10 +8,11 @@ Implements many of the main functions used to call PROPKA.
import logging import logging
import argparse import argparse
from pathlib import Path from pathlib import Path
from typing import Iterable, Iterator, List, TYPE_CHECKING, NoReturn, Optional, Tuple, TypeVar from typing import Dict, Iterable, Iterator, List, TYPE_CHECKING, NoReturn, Optional, Tuple, TypeVar
if TYPE_CHECKING: if TYPE_CHECKING:
from propka.atom import Atom from propka.atom import Atom
from propka.conformation_container import ConformationContainer
T = TypeVar("T") T = TypeVar("T")
@@ -30,7 +31,6 @@ EXPECTED_ATOM_NUMBERS = {'ALA': 5, 'ARG': 11, 'ASN': 8, 'ASP': 8, 'CYS': 6,
class Options: class Options:
# Note: All the "NoReturn" members appear to be unused # Note: All the "NoReturn" members appear to be unused
alignment: NoReturn # Optional[List[str]]
chains: Optional[List[str]] chains: Optional[List[str]]
display_coupled_residues: bool = False display_coupled_residues: bool = False
filenames: List[str] # List[Path]? filenames: List[str] # List[Path]?
@@ -38,20 +38,17 @@ class Options:
input_pdb: str # Path? input_pdb: str # Path?
keep_protons: bool = False keep_protons: bool = False
log_level: str = 'INFO' log_level: str = 'INFO'
mutations: NoReturn # Optional[List[str]]
mutator: NoReturn # Optional[str] # alignment/scwrl/jackal
mutator_options: NoReturn # Optional[List[str]]
pH: NoReturn # float = 7.0 pH: NoReturn # float = 7.0
parameters: Path parameters: Path
protonate_all: bool = False protonate_all: bool = False
reference: NoReturn # str = 'neutral' reference: NoReturn # str = 'neutral'
reuse_ligand_mol2_file: bool = False # only used by unused function reuse_ligand_mol2_file: bool = False # only used by unused function
thermophiles: NoReturn # Optional[List[str]]
titrate_only: Optional[List[_T_RESIDUE_TUPLE]] titrate_only: Optional[List[_T_RESIDUE_TUPLE]]
window: Tuple[float, float, float] = (0.0, 14.0, 1.0) window: Tuple[float, float, float] = (0.0, 14.0, 1.0)
def protein_precheck(conformations, names): def protein_precheck(conformations: Dict[str, "ConformationContainer"],
names: Iterable[str]):
"""Check protein for correct number of atoms, etc. """Check protein for correct number of atoms, etc.
Args: Args:
@@ -60,7 +57,7 @@ def protein_precheck(conformations, names):
for name in names: for name in names:
atoms = conformations[name].atoms atoms = conformations[name].atoms
# Group the atoms by their residue: # Group the atoms by their residue:
atoms_by_residue = {} atoms_by_residue: Dict[str, List[Atom]] = {}
for atom in atoms: for atom in atoms:
if atom.element != 'H': if atom.element != 'H':
res_id = resid_from_atom(atom) res_id = resid_from_atom(atom)
@@ -272,18 +269,6 @@ def build_parser(parser=None):
help=('Treat only the specified residues as titratable. Value should ' help=('Treat only the specified residues as titratable. Value should '
'be a comma-separated list of "chain:resnum" values; for ' 'be a comma-separated list of "chain:resnum" values; for '
'example: -i "A:10,A:11"')) 'example: -i "A:10,A:11"'))
group.add_argument(
"-t", "--thermophile", action="append", dest="thermophiles",
help=("defining a thermophile filename; usually used in "
"'alignment-mutations'"))
group.add_argument(
"-a", "--alignment", action="append", dest="alignment",
help=("alignment file connecting <filename> and <thermophile> "
"[<thermophile>.pir]"))
group.add_argument(
"-m", "--mutation", action="append", dest="mutations",
help=("specifying mutation labels which is used to modify "
"<filename> according to, e.g. N25R/N181D"))
group.add_argument( group.add_argument(
"--version", action="version", version=f"%(prog)s {propka.__version__}") "--version", action="version", version=f"%(prog)s {propka.__version__}")
group.add_argument( group.add_argument(
@@ -311,16 +296,6 @@ def build_parser(parser=None):
default=(0.0, 14.0, 0.1), default=(0.0, 14.0, 0.1),
help=("setting the pH-grid to calculate e.g. stability " help=("setting the pH-grid to calculate e.g. stability "
"related properties [0.0, 14.0, 0.1]")) "related properties [0.0, 14.0, 0.1]"))
group.add_argument(
"--mutator", dest="mutator",
help=(
"setting approach for mutating <filename> "
"[alignment/scwrl/jackal]"
)
)
group.add_argument(
"--mutator-option", dest="mutator_options", action="append",
help="setting property for mutator [e.g. type=\"side-chain\"]")
group.add_argument( group.add_argument(
"-d", "--display-coupled-residues", dest="display_coupled_residues", "-d", "--display-coupled-residues", dest="display_coupled_residues",
action="store_true", action="store_true",

View File

@@ -195,7 +195,7 @@ class MolecularContainer:
stability_range = (min(stable_values), max(stable_values)) stability_range = (min(stable_values), max(stable_values))
return profile, opt, range_80pct, stability_range return profile, opt, range_80pct, stability_range
def get_charge_profile(self, conformation: str = 'AVR', grid=[0., 14., .1]): def get_charge_profile(self, conformation: str = 'AVR', grid=(0., 14., .1)):
"""Get charge profile for conformation as function of pH. """Get charge profile for conformation as function of pH.
Args: Args:
@@ -212,13 +212,13 @@ class MolecularContainer:
charge_profile.append([ph, q_unfolded, q_folded]) charge_profile.append([ph, q_unfolded, q_folded])
return charge_profile return charge_profile
def get_pi(self, conformation: str = 'AVR', grid=[0., 14., 1], *, def get_pi(self, conformation: str = 'AVR', grid=(0., 14.), *,
precision: float = 1e-4) -> Tuple[float, float]: precision: float = 1e-4) -> Tuple[float, float]:
"""Get the isoelectric points for folded and unfolded states. """Get the isoelectric points for folded and unfolded states.
Args: Args:
conformation: conformation to test conformation: conformation to test
grid: grid of pH values [min, max, step] grid: pH window [min, max]
precision: Compute pI up to this precision precision: Compute pI up to this precision
Returns: Returns:
1. Folded state PI 1. Folded state PI

View File

@@ -14,7 +14,7 @@ from datetime import date
from decimal import Decimal from decimal import Decimal
from os import PathLike from os import PathLike
from pathlib import Path from pathlib import Path
from typing import IO, AnyStr, List, NoReturn, Optional, Union, TYPE_CHECKING from typing import IO, AnyStr, List, Optional, Tuple, Union, TYPE_CHECKING
import warnings import warnings
from .parameters import Parameters from .parameters import Parameters
@@ -52,20 +52,6 @@ def open_file_for_writing(input_file: _TextIOSource) -> IO[str]:
return input_file return input_file
def write_file(filename, lines):
"""Writes a new file.
Args:
filename: name of file
lines: lines to write to file
"""
warnings.warn("unused and untested by propka")
file_ = open_file_for_writing(filename)
for line in lines:
file_.write("{0:s}\n".format(line))
file_.close()
def print_header(): def print_header():
"""Print header section of output.""" """Print header section of output."""
str_ = "{0:s}\n".format(get_propka_header()) str_ = "{0:s}\n".format(get_propka_header())
@@ -74,46 +60,6 @@ def print_header():
_LOGGER.info("\n%s", str_) _LOGGER.info("\n%s", str_)
def write_pdb_for_protein(
protein, pdbfile=None, filename=None, include_hydrogens=False, _=None):
"""Write a residue to the new PDB file.
Args:
protein: protein object
pdbfile: PDB file
filename: file to write to
include_hydrogens: Boolean indicating whether to include hydrogens
options: options object
"""
raise NotImplementedError("unused")
if pdbfile is None:
# opening file if not given
if filename is None:
filename = "{0:s}.pdb".format(protein.name)
# TODO - this would be better as a context manager
pdbfile = open(filename, 'w')
_LOGGER.info("writing pdbfile {0:s}".format(filename))
close_file = True
else:
# don't close the file, it was opened in a different place
close_file = False
numb = 0
for chain in protein.chains:
for residue in chain.residues:
if residue.res_name not in ["N+ ", "C- "]:
for atom in residue.atoms:
if (not include_hydrogens) and atom.name[0] == "H":
# don't print
pass
else:
numb += 1
line = atom.make_pdb_line2(numb=numb)
line += "\n"
pdbfile.write(line)
if close_file:
pdbfile.close()
def write_pdb_for_conformation(conformation: "ConformationContainer", def write_pdb_for_conformation(conformation: "ConformationContainer",
filename: _PathArg): filename: _PathArg):
"""Write PDB conformation to a file. """Write PDB conformation to a file.
@@ -129,22 +75,19 @@ def write_pdb_for_conformation(conformation: "ConformationContainer",
def write_pka(protein: "MolecularContainer", def write_pka(protein: "MolecularContainer",
parameters: Parameters, parameters: Parameters,
filename: Optional[_PathArg] = None, filename: Optional[_PathArg] = None,
conformation='1A', conformation: str = '1A',
reference="neutral", _="folding", verbose=False, reference: str = "neutral",
__=None): *,
verbose: bool = True):
"""Write the pKa-file based on the given protein. """Write the pKa-file based on the given protein.
Args: Args:
protein: protein object protein: protein object
filename: output file name filename: output file name
conformation: TODO - figure this out conformation: specific conformation
reference: reference state reference: reference state
_: "folding" or other
verbose: Boolean flag for verbosity verbose: Boolean flag for verbosity
__: options object
""" """
# TODO - the code immediately overrides the verbose argument; why?
verbose = True
if filename is None: if filename is None:
filename = "{0:s}.pka".format(protein.name) filename = "{0:s}.pka".format(protein.name)
if verbose: if verbose:
@@ -168,39 +111,6 @@ def write_pka(protein: "MolecularContainer",
Path(filename).write_text(str_, encoding="utf-8") Path(filename).write_text(str_, encoding="utf-8")
def print_tm_profile(protein: NoReturn, reference="neutral", window=[0., 14., 1.],
__=[0., 0.], tms=None, ref=None, _=False,
options=None):
"""Print Tm profile.
I think Tm refers to the denaturation temperature.
Args:
protein: protein object
reference: reference state
window: pH window [min, max, step]
__: temperature range [min, max]
tms: TODO - figure this out
ref: TODO - figure this out (probably reference state?)
_: Boolean for verbosity
options: options object
"""
raise NotImplementedError("unused")
profile = protein.getTmProfile(
reference=reference, grid=[0., 14., 0.1], tms=tms, ref=ref,
options=options)
if profile is None:
str_ = "Could not determine Tm-profile\n"
else:
str_ = " suggested Tm-profile for {0:s}\n".format(protein.name)
for (ph, tm_) in profile:
if (ph >= window[0] and ph <= window[1]
and (ph % window[2] < 0.01
or ph % window[2] > 0.99*window[2])):
str_ += "{0:>6.2f}{1:>10.2f}\n".format(ph, tm_)
_LOGGER.info(str_)
def print_result(protein: "MolecularContainer", conformation: str, parameters: Parameters): def print_result(protein: "MolecularContainer", conformation: str, parameters: Parameters):
"""Prints all resulting output from determinants and down. """Prints all resulting output from determinants and down.
@@ -283,8 +193,11 @@ def get_summary_section(protein: "MolecularContainer", conformation: str,
def get_folding_profile_section( def get_folding_profile_section(
protein: "MolecularContainer", protein: "MolecularContainer",
conformation='AVR', direction="folding", reference="neutral", conformation: str = 'AVR',
window=[0., 14., 1.0], _=False, __=None): direction: str = "folding",
reference: str = "neutral",
window: Tuple[float, float, float] = (0., 14., 1.),
):
"""Returns string with the folding profile section of the results. """Returns string with the folding profile section of the results.
Args: Args:
@@ -293,8 +206,6 @@ def get_folding_profile_section(
direction: 'folding' or other direction: 'folding' or other
reference: reference state reference: reference state
window: pH window [min, max, step] window: pH window [min, max, step]
_: Boolean for verbose output
__: options object
Returns: Returns:
string string
""" """
@@ -340,7 +251,8 @@ def get_folding_profile_section(
return str_ return str_
def get_charge_profile_section(protein, conformation='AVR', _=None): def get_charge_profile_section(protein: "MolecularContainer",
conformation: str = 'AVR'):
"""Returns string with the charge profile section of the results. """Returns string with the charge profile section of the results.
Args: Args:
@@ -371,34 +283,6 @@ def get_charge_profile_section(protein, conformation='AVR', _=None):
return str_ return str_
def write_jackal_scap_file(mutation_data=None, filename="1xxx_scap.list",
_=None):
"""Write a scap file for, i.e., generating a mutated protein
TODO - figure out what this is
"""
raise NotImplementedError("unused")
with open(filename, 'w') as file_:
for chain_id, _, res_num, code2 in mutation_data:
str_ = "{chain:s}, {num:d}, {code:s}\n".format(
chain=chain_id, num=res_num, code=code2)
file_.write(str_)
def write_scwrl_sequence_file(sequence, filename="x-ray.seq", _=None):
"""Write a scwrl sequence file for, e.g., generating a mutated protein
TODO - figure out what this is
"""
warnings.warn("unused and untested by propka")
with open(filename, 'w') as file_:
start = 0
while len(sequence[start:]) > 60:
file_.write("{0:s}s\n".format(sequence[start:start+60]))
start += 60
file_.write("{0:s}\n".format(sequence[start:]))
def get_propka_header(): def get_propka_header():
"""Create the header. """Create the header.

View File

@@ -12,7 +12,7 @@ in configuration file.
""" """
import logging import logging
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict, List from typing import Callable, Dict, List, Sequence, Tuple, TypeVar, Union
try: try:
# New in version 3.10, deprecated since version 3.12 # New in version 3.10, deprecated since version 3.12
@@ -39,6 +39,8 @@ class squared_property:
setattr(instance, self._name_not_squared, value**0.5) setattr(instance, self._name_not_squared, value**0.5)
T = TypeVar("T")
_T_MATRIX: TypeAlias = "InteractionMatrix" _T_MATRIX: TypeAlias = "InteractionMatrix"
_T_PAIR_WISE_MATRIX: TypeAlias = "PairwiseMatrix" _T_PAIR_WISE_MATRIX: TypeAlias = "PairwiseMatrix"
_T_NUMBER_DICTIONARY = Dict[str, float] _T_NUMBER_DICTIONARY = Dict[str, float]
@@ -118,13 +120,10 @@ class Parameters:
CYS_CYS_exception: float = 3.60 CYS_CYS_exception: float = 3.60
min_ligand_model_pka: float = -10.0 min_ligand_model_pka: float = -10.0
max_ligand_model_pka: float = 20.0 max_ligand_model_pka: float = 20.0
# include_H_in_interactions: NoReturn = None
coupling_max_number_of_bonds: int = 3 coupling_max_number_of_bonds: int = 3
min_bond_distance_for_hydrogen_bonds: int = 4 min_bond_distance_for_hydrogen_bonds: int = 4
# coupling_penalty: NoReturn = None
shared_determinants: _T_BOOL = False shared_determinants: _T_BOOL = False
common_charge_centre: _T_BOOL = False common_charge_centre: _T_BOOL = False
# hide_penalised_group: NoReturn = None
remove_penalised_group: _T_BOOL = True remove_penalised_group: _T_BOOL = True
max_intrinsic_pka_diff: float = 2.0 max_intrinsic_pka_diff: float = 2.0
min_interaction_energy: float = 0.5 min_interaction_energy: float = 0.5
@@ -158,8 +157,10 @@ class Parameters:
self.parse_to_matrix(words) self.parse_to_matrix(words)
elif typeannotation is _T_STRING_DICTIONARY: elif typeannotation is _T_STRING_DICTIONARY:
self.parse_to_string_dictionary(words) self.parse_to_string_dictionary(words)
elif typeannotation is int or typeannotation is _T_BOOL:
self.parse_parameter(words, int)
else: else:
self.parse_parameter(words) self.parse_parameter(words, float)
def parse_to_number_dictionary(self, words): def parse_to_number_dictionary(self, words):
"""Parse field to number dictionary. """Parse field to number dictionary.
@@ -222,14 +223,14 @@ class Parameters:
value = tuple(words[1:]) value = tuple(words[1:])
matrix.add(value) matrix.add(value)
def parse_parameter(self, words): def parse_parameter(self, words, typefunc: Callable[[str], T]):
"""Parse field to parameters. """Parse field to parameters.
Args: Args:
words: strings to parse words: strings to parse
""" """
assert len(words) == 2, words assert len(words) == 2, words
value = float(words[1]) value = typefunc(words[1])
setattr(self, words[0], value) setattr(self, words[0], value)
def parse_string(self, words): def parse_string(self, words):
@@ -451,37 +452,40 @@ O2
class InteractionMatrix: class InteractionMatrix:
"""Interaction matrix class.""" """Interaction matrix class."""
def __init__(self, name): def __init__(self, name: str):
"""Initialize with name of matrix. """Initialize with name of matrix.
Args: Args:
name: name of interaction matrix name: name of interaction matrix
""" """
self.name = name self.name = name
self.value = None self.ordered_keys: List[str] = []
self.ordered_keys = [] self.dictionary: Dict[str, Dict[str, Union[str, float]]] = {}
self.dictionary = {}
def add(self, words): def add(self, words: Sequence[str]):
"""Add values to matrix. """Add values to matrix.
Args: Args:
words: values to add words: values to add
""" """
len_expected = len(self.ordered_keys) + 2
if len(words) != len_expected:
raise ValueError(f"Expected {len_expected} arguments, got {words!r}")
new_group = words[0] new_group = words[0]
self.ordered_keys.append(new_group) self.ordered_keys.append(new_group)
if new_group not in self.dictionary.keys(): if new_group not in self.dictionary.keys():
self.dictionary[new_group] = {} self.dictionary[new_group] = {}
for i, group in enumerate(self.ordered_keys): for i, group in enumerate(self.ordered_keys):
if len(words) > i+1: if len(words) > i+1:
value: Union[str, float]
try: try:
self.value = float(words[i+1]) value = float(words[i+1])
except ValueError: except ValueError:
self.value = words[i+1] value = words[i+1]
self.dictionary[group][new_group] = self.value self.dictionary[group][new_group] = value
self.dictionary[new_group][group] = self.value self.dictionary[new_group][group] = value
def get_value(self, item1, item2): def get_value(self, item1: str, item2: str) -> Union[str, float, None]:
"""Get specific matrix value. """Get specific matrix value.
Args: Args:
@@ -495,7 +499,7 @@ class InteractionMatrix:
except KeyError: except KeyError:
return None return None
def __getitem__(self, group): def __getitem__(self, group: str):
"""Get specific group from matrix. """Get specific group from matrix.
Args: Args:
@@ -531,17 +535,17 @@ class InteractionMatrix:
class PairwiseMatrix: class PairwiseMatrix:
"""Pairwise interaction matrix class.""" """Pairwise interaction matrix class."""
def __init__(self, name): def __init__(self, name: str):
"""Initialize pairwise matrix. """Initialize pairwise matrix.
Args: Args:
name: name of pairwise interaction name: name of pairwise interaction
""" """
self.name = name self.name = name
self.dictionary = {} self.dictionary: Dict[str, Dict[str, Tuple[float, float]]] = {}
self.default = [0.0, 0.0] self.default = (0.0, 0.0)
def add(self, words): def add(self, words: Sequence[str]):
"""Add information to the matrix. """Add information to the matrix.
TODO - this function unnecessarily bundles arguments into a tuple TODO - this function unnecessarily bundles arguments into a tuple
@@ -551,16 +555,17 @@ class PairwiseMatrix:
""" """
# assign the default value # assign the default value
if len(words) == 3 and words[0] == 'default': if len(words) == 3 and words[0] == 'default':
self.default = [float(words[1]), float(words[2])] self.default = (float(words[1]), float(words[2]))
return return
# assign non-default values # assign non-default values
assert len(words) == 4
group1 = words[0] group1 = words[0]
group2 = words[1] group2 = words[1]
value = [float(words[2]), float(words[3])] value = (float(words[2]), float(words[3]))
self.insert(group1, group2, value) self.insert(group1, group2, value)
self.insert(group2, group1, value) self.insert(group2, group1, value)
def insert(self, key1, key2, value): def insert(self, key1: str, key2: str, value: Tuple[float, float]):
"""Insert value into matrix. """Insert value into matrix.
Args: Args:
@@ -578,7 +583,7 @@ class PairwiseMatrix:
self.dictionary[key1] = {} self.dictionary[key1] = {}
self.dictionary[key1][key2] = value self.dictionary[key1][key2] = value
def get_value(self, item1, item2): def get_value(self, item1: str, item2: str) -> Tuple[float, float]:
"""Get specified value from matrix. """Get specified value from matrix.
Args: Args:
@@ -592,7 +597,7 @@ class PairwiseMatrix:
except KeyError: except KeyError:
return self.default return self.default
def __getitem__(self, group): def __getitem__(self, group: str):
"""Get item from matrix corresponding to specific group. """Get item from matrix corresponding to specific group.
Args: Args:

View File

@@ -7,6 +7,7 @@ Contains version-specific methods and parameters.
TODO - this module unnecessarily confuses the code. Can we eliminate it? TODO - this module unnecessarily confuses the code. Can we eliminate it?
""" """
import logging import logging
from typing import Sequence, Tuple
from propka.atom import Atom from propka.atom import Atom
from propka.hydrogens import setup_bonding_and_protonation, setup_bonding from propka.hydrogens import setup_bonding_and_protonation, setup_bonding
from propka.hydrogens import setup_bonding_and_protonation_30_style from propka.hydrogens import setup_bonding_and_protonation_30_style
@@ -15,6 +16,7 @@ from propka.energy import hydrogen_bond_energy, hydrogen_bond_interaction
from propka.energy import electrostatic_interaction, check_coulomb_pair from propka.energy import electrostatic_interaction, check_coulomb_pair
from propka.energy import coulomb_energy, check_exceptions from propka.energy import coulomb_energy, check_exceptions
from propka.energy import backbone_reorganization from propka.energy import backbone_reorganization
from propka.parameters import Parameters
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -22,7 +24,7 @@ _LOGGER = logging.getLogger(__name__)
class Version: class Version:
"""Store version-specific methods and parameters.""" """Store version-specific methods and parameters."""
def __init__(self, parameters): def __init__(self, parameters: Parameters):
self.parameters = parameters self.parameters = parameters
self.desolvation_model = self.empty_function self.desolvation_model = self.empty_function
self.weight_pair_method = self.empty_function self.weight_pair_method = self.empty_function
@@ -99,7 +101,7 @@ class Version:
"""Setup bonding using assigned model.""" """Setup bonding using assigned model."""
return self.prepare_bonds(self.parameters, molecular_container) return self.prepare_bonds(self.parameters, molecular_container)
def get_hydrogen_bond_parameters(self, atom1: Atom, atom2: Atom) -> tuple: def get_hydrogen_bond_parameters(self, atom1: Atom, atom2: Atom) -> Tuple[float, Sequence[float]]:
"""Get hydrogen bond parameters for two atoms.""" """Get hydrogen bond parameters for two atoms."""
raise NotImplementedError("abstract method") raise NotImplementedError("abstract method")
@@ -136,7 +138,7 @@ class VersionA(Version):
dpka_max = self.parameters.sidechain_interaction dpka_max = self.parameters.sidechain_interaction
cutoff = self.parameters.sidechain_cutoffs.get_value( cutoff = self.parameters.sidechain_cutoffs.get_value(
atom1.group_type, atom2.group_type) atom1.group_type, atom2.group_type)
return [dpka_max, cutoff] return dpka_max, cutoff
def get_backbone_hydrogen_bond_parameters(self, backbone_atom, atom): def get_backbone_hydrogen_bond_parameters(self, backbone_atom, atom):
"""Get hydrogen bond parameters between backbone atom and other atom. """Get hydrogen bond parameters between backbone atom and other atom.
@@ -311,4 +313,4 @@ class Propka30(Version):
atom1.group_type, atom2.group_type) atom1.group_type, atom2.group_type)
cutoff = self.parameters.sidechain_cutoffs.get_value( cutoff = self.parameters.sidechain_cutoffs.get_value(
atom1.group_type, atom2.group_type) atom1.group_type, atom2.group_type)
return [dpka_max, cutoff] return dpka_max, cutoff