Typing: Options
This commit is contained in:
@@ -6,7 +6,8 @@ Container data structure for molecular conformations.
|
||||
"""
|
||||
import logging
|
||||
import functools
|
||||
from typing import Iterable, List, NoReturn, Optional, TYPE_CHECKING, Set
|
||||
from typing import Callable, Dict, Iterable, Iterator, List, NoReturn, Optional, TYPE_CHECKING, Set
|
||||
|
||||
from propka.lib import Options
|
||||
from propka.version import Version
|
||||
|
||||
@@ -26,6 +27,8 @@ from propka.parameters import Parameters
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CallableGroupToGroups = Callable[[Group], List[Group]]
|
||||
|
||||
|
||||
#: A large number that gets multipled with the integer obtained from applying
|
||||
#: :func:`ord` to the atom chain ID. Used in calculating atom keys for
|
||||
@@ -276,7 +279,7 @@ class ConformationContainer:
|
||||
return penalised_labels
|
||||
|
||||
@staticmethod
|
||||
def share_determinants(groups):
|
||||
def share_determinants(groups: Iterable[Group]):
|
||||
"""Share sidechain, backbone, and Coloumb determinants between groups.
|
||||
|
||||
Args:
|
||||
@@ -286,7 +289,7 @@ class ConformationContainer:
|
||||
types = ['sidechain', 'backbone', 'coulomb']
|
||||
for type_ in types:
|
||||
# find maximum value for each determinant
|
||||
max_dets = {}
|
||||
max_dets: Dict[Group, float] = {}
|
||||
for group in groups:
|
||||
for det in group.determinants[type_]:
|
||||
# update max dets
|
||||
@@ -302,7 +305,11 @@ class ConformationContainer:
|
||||
for group in groups:
|
||||
group.set_determinant(new_determinant, type_)
|
||||
|
||||
def get_coupled_systems(self, groups, get_coupled_groups):
|
||||
def get_coupled_systems(
|
||||
self,
|
||||
groups: Iterable[Group],
|
||||
get_coupled_groups: CallableGroupToGroups,
|
||||
) -> Iterator[Set[Group]]:
|
||||
"""A generator that yields covalently coupled systems.
|
||||
|
||||
Args:
|
||||
@@ -314,15 +321,16 @@ class ConformationContainer:
|
||||
groups = set(groups)
|
||||
while len(groups) > 0:
|
||||
# extract a system of coupled groups ...
|
||||
system = set()
|
||||
system: Set[Group] = set()
|
||||
self.get_a_coupled_system_of_groups(
|
||||
groups.pop(), system, get_coupled_groups)
|
||||
# ... and remove them from the list
|
||||
groups -= system
|
||||
yield system
|
||||
|
||||
def get_a_coupled_system_of_groups(self, new_group, coupled_groups,
|
||||
get_coupled_groups):
|
||||
def get_a_coupled_system_of_groups(self, new_group: Group,
|
||||
coupled_groups: Set[Group],
|
||||
get_coupled_groups: CallableGroupToGroups):
|
||||
"""Set up coupled systems of groups.
|
||||
|
||||
Args:
|
||||
@@ -353,7 +361,7 @@ class ConformationContainer:
|
||||
reference=reference)
|
||||
return ddg
|
||||
|
||||
def calculate_charge(self, parameters, ph: float):
|
||||
def calculate_charge(self, parameters: Parameters, ph: float):
|
||||
"""Calculate charge for folded and unfolded states.
|
||||
|
||||
Args:
|
||||
@@ -371,7 +379,7 @@ class ConformationContainer:
|
||||
state='folded')
|
||||
return unfolded, folded
|
||||
|
||||
def get_backbone_groups(self):
|
||||
def get_backbone_groups(self) -> List[Group]:
|
||||
"""Get backbone groups needed for the pKa calculations.
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -6,9 +6,11 @@ Describe and analyze energetic coupling between groups.
|
||||
"""
|
||||
import logging
|
||||
import itertools
|
||||
from typing import Optional
|
||||
import propka.lib
|
||||
from propka.group import Group
|
||||
from propka.output import make_interaction_map
|
||||
from propka.parameters import Parameters
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -16,9 +18,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class NonCovalentlyCoupledGroups:
|
||||
"""Groups that are coupled without covalent bonding."""
|
||||
def __init__(self):
|
||||
self.parameters = None
|
||||
self.do_prot_stat = True
|
||||
parameters: Optional[Parameters] = None
|
||||
do_prot_stat = True
|
||||
|
||||
def is_coupled_protonation_state_probability(self, group1, group2,
|
||||
energy_method,
|
||||
@@ -264,7 +265,7 @@ class NonCovalentlyCoupledGroups:
|
||||
_LOGGER.info(swap_info)
|
||||
|
||||
@staticmethod
|
||||
def get_interaction(group1, group2, include_side_chain_hbs=True):
|
||||
def get_interaction(group1: Group, group2: Group, include_side_chain_hbs=True):
|
||||
"""Get interaction energy between two groups.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -15,6 +15,11 @@ Provides the :class:`Determinant` class.
|
||||
|
||||
"""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from propka.group import Group
|
||||
|
||||
|
||||
class Determinant:
|
||||
"""Determinant class.
|
||||
@@ -25,7 +30,7 @@ class Determinant:
|
||||
TODO - figure out what this class does.
|
||||
"""
|
||||
|
||||
def __init__(self, group, value):
|
||||
def __init__(self, group: "Group", value: float):
|
||||
"""Initialize the object.
|
||||
|
||||
Args:
|
||||
@@ -36,7 +41,7 @@ class Determinant:
|
||||
self.label = group.label
|
||||
self.value = value
|
||||
|
||||
def add(self, value):
|
||||
def add(self, value: float):
|
||||
"""Increment determinant value.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -9,8 +9,7 @@ Input routines.
|
||||
Methods to read PROPKA input files (:func:`read_propka` and
|
||||
:func:`get_atom_lines_from_input`) have been removed.
|
||||
"""
|
||||
import typing
|
||||
from typing import Iterator, Tuple, Union
|
||||
from typing import IO, ContextManager, Dict, Iterable, Iterator, Optional, Tuple
|
||||
import contextlib
|
||||
import io
|
||||
import zipfile
|
||||
@@ -19,19 +18,18 @@ from propka.lib import protein_precheck
|
||||
from propka.atom import Atom
|
||||
from propka.conformation_container import ConformationContainer
|
||||
from propka.molecular_container import MolecularContainer
|
||||
from propka.output import _PathArg, _PathLikeTypes, _TextIOSource
|
||||
from propka.parameters import Parameters
|
||||
|
||||
|
||||
def open_file_for_reading(
|
||||
input_file: typing.Union[str, Path, typing.TextIO]
|
||||
) -> typing.ContextManager[typing.TextIO]:
|
||||
def open_file_for_reading(input_file: _TextIOSource) -> ContextManager[IO[str]]:
|
||||
"""Open file or file-like stream for reading.
|
||||
|
||||
Args:
|
||||
input_file: path to file or file-like object. If file-like object,
|
||||
then will attempt seek(0).
|
||||
"""
|
||||
if not isinstance(input_file, (str, Path)):
|
||||
if not isinstance(input_file, _PathLikeTypes):
|
||||
input_file.seek(0)
|
||||
return contextlib.nullcontext(input_file)
|
||||
|
||||
@@ -48,7 +46,11 @@ def open_file_for_reading(
|
||||
return contextlib.closing(open(input_file, 'rt'))
|
||||
|
||||
|
||||
def read_molecule_file(filename: str, mol_container: MolecularContainer, stream=None) -> MolecularContainer:
|
||||
def read_molecule_file(
|
||||
filename: _PathArg,
|
||||
mol_container: MolecularContainer,
|
||||
stream: Optional[IO[str]] = None,
|
||||
) -> MolecularContainer:
|
||||
"""Read input file or stream (PDB or PROPKA) for a molecular container
|
||||
|
||||
Args:
|
||||
@@ -96,11 +98,7 @@ def read_molecule_file(filename: str, mol_container: MolecularContainer, stream=
|
||||
input_path = Path(filename)
|
||||
mol_container.name = input_path.stem
|
||||
input_file_extension = input_path.suffix
|
||||
|
||||
if stream is not None:
|
||||
input_file = stream
|
||||
else:
|
||||
input_file = filename
|
||||
input_file = filename if stream is None else stream
|
||||
|
||||
if input_file_extension.lower() == '.pdb':
|
||||
# input is a pdb file. read in atoms and top up containers to make
|
||||
@@ -133,7 +131,7 @@ def read_molecule_file(filename: str, mol_container: MolecularContainer, stream=
|
||||
return mol_container
|
||||
|
||||
|
||||
def read_parameter_file(input_file: Union[Path, str], parameters: Parameters) -> Parameters:
|
||||
def read_parameter_file(input_file: _PathArg, parameters: Parameters) -> Parameters:
|
||||
"""Read a parameter file.
|
||||
|
||||
Args:
|
||||
@@ -161,8 +159,13 @@ def conformation_sorter(conf: str) -> int:
|
||||
return model*100+ord(altloc)
|
||||
|
||||
|
||||
def get_atom_lines_from_pdb(pdb_file, ignore_residues=[], keep_protons=False,
|
||||
tags=['ATOM ', 'HETATM'], chains=None) -> Iterator[Tuple[str, Atom]]:
|
||||
def get_atom_lines_from_pdb(
|
||||
pdb_file: _TextIOSource,
|
||||
ignore_residues: Iterable[str] = (),
|
||||
keep_protons: bool = False,
|
||||
tags: Iterable[str] = ('ATOM ', 'HETATM'),
|
||||
chains: Optional[Iterable[str]] = None,
|
||||
) -> Iterator[Tuple[str, Atom]]:
|
||||
"""Get atom lines from PDB file.
|
||||
|
||||
Args:
|
||||
@@ -228,7 +231,8 @@ def get_atom_lines_from_pdb(pdb_file, ignore_residues=[], keep_protons=False,
|
||||
terminal = None
|
||||
|
||||
|
||||
def read_pdb(pdb_file, parameters, molecule):
|
||||
def read_pdb(pdb_file: _TextIOSource, parameters: Parameters,
|
||||
molecule: MolecularContainer):
|
||||
"""Parse a PDB file.
|
||||
|
||||
Args:
|
||||
@@ -240,7 +244,7 @@ def read_pdb(pdb_file, parameters, molecule):
|
||||
1. list of conformations
|
||||
2. list of names
|
||||
"""
|
||||
conformations = {}
|
||||
conformations: Dict[str, ConformationContainer] = {}
|
||||
# read in all atoms in the file
|
||||
lines = get_atom_lines_from_pdb(
|
||||
pdb_file, ignore_residues=parameters.ignore_residues,
|
||||
@@ -253,4 +257,4 @@ def read_pdb(pdb_file, parameters, molecule):
|
||||
conformations[name].add_atom(atom)
|
||||
# make a sorted list of conformation names
|
||||
names = sorted(conformations.keys(), key=conformation_sorter)
|
||||
return [conformations, names]
|
||||
return conformations, names
|
||||
|
||||
@@ -304,7 +304,7 @@ def add_determinants(iterative_interactions: List[Interaction], version: Version
|
||||
for itres in iteratives:
|
||||
for type_ in ['sidechain', 'backbone', 'coulomb']:
|
||||
for interaction in itres.determinants[type_]:
|
||||
value = interaction[1]
|
||||
value: float = interaction[1]
|
||||
if value > UNK_MIN_VALUE or value < -UNK_MIN_VALUE:
|
||||
group = interaction[0]
|
||||
new_det = Determinant(group, value)
|
||||
|
||||
@@ -5,16 +5,20 @@ Set-up of a PROPKA calculation
|
||||
Implements many of the main functions used to call PROPKA.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import List, TYPE_CHECKING
|
||||
from typing import Iterable, Iterator, List, TYPE_CHECKING, NoReturn, Optional, Tuple, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from propka.atom import Atom
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
Number = TypeVar("Number", int, float)
|
||||
|
||||
_T_RESIDUE_TUPLE = Tuple[str, int, str]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -23,7 +27,28 @@ EXPECTED_ATOM_NUMBERS = {'ALA': 5, 'ARG': 11, 'ASN': 8, 'ASP': 8, 'CYS': 6,
|
||||
'LEU': 8, 'LYS': 9, 'MET': 8, 'PHE': 11, 'PRO': 7,
|
||||
'SER': 6, 'THR': 7, 'TRP': 14, 'TYR': 12, 'VAL': 7}
|
||||
|
||||
Options = argparse.Namespace
|
||||
|
||||
class Options:
|
||||
# Note: All the "NoReturn" members appear to be unused
|
||||
alignment: NoReturn # Optional[List[str]]
|
||||
chains: Optional[List[str]]
|
||||
display_coupled_residues: bool = False
|
||||
filenames: List[str] # List[Path]?
|
||||
grid: Tuple[float, float, float] = (0.0, 14.0, 0.1)
|
||||
input_pdb: str # Path?
|
||||
keep_protons: bool = False
|
||||
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
|
||||
parameters: Path
|
||||
protonate_all: bool = False
|
||||
reference: NoReturn # str = 'neutral'
|
||||
reuse_ligand_mol2_file: bool = False # only used by unused function
|
||||
thermophiles: NoReturn # Optional[List[str]]
|
||||
titrate_only: Optional[List[_T_RESIDUE_TUPLE]]
|
||||
window: Tuple[float, float, float] = (0.0, 14.0, 1.0)
|
||||
|
||||
|
||||
def protein_precheck(conformations, names):
|
||||
@@ -112,11 +137,11 @@ def make_molecule(atom: "Atom", atoms: List["Atom"]):
|
||||
return res_atoms
|
||||
|
||||
|
||||
def make_grid(min_, max_, step):
|
||||
def make_grid(min_: Number, max_: Number, step: Number) -> Iterator[Number]:
|
||||
"""Make a grid across the specified tange.
|
||||
|
||||
TODO - figure out if this duplicates existing generators like `range` or
|
||||
numpy function.
|
||||
Like range() for integers or numpy.arange() for floats, except that `max_`
|
||||
is not excluded from the range.
|
||||
|
||||
Args:
|
||||
min_: minimum value of grid
|
||||
@@ -129,7 +154,7 @@ def make_grid(min_, max_, step):
|
||||
x += step
|
||||
|
||||
|
||||
def generate_combinations(interactions):
|
||||
def generate_combinations(interactions: Iterable[T]) -> List[List[T]]:
|
||||
"""Generate combinations of interactions.
|
||||
|
||||
Args:
|
||||
@@ -137,14 +162,14 @@ def generate_combinations(interactions):
|
||||
Returns:
|
||||
list of combinations
|
||||
"""
|
||||
res = [[]]
|
||||
res: List[List[T]] = [[]]
|
||||
for interaction in interactions:
|
||||
res = make_combination(res, interaction)
|
||||
res.remove([])
|
||||
return res
|
||||
|
||||
|
||||
def make_combination(combis, interaction):
|
||||
def make_combination(combis: List[List[T]], interaction: T) -> List[List[T]]:
|
||||
"""Make a specific set of combinations.
|
||||
|
||||
Args:
|
||||
@@ -160,7 +185,7 @@ def make_combination(combis, interaction):
|
||||
return res
|
||||
|
||||
|
||||
def parse_res_string(res_str):
|
||||
def parse_res_string(res_str: str) -> _T_RESIDUE_TUPLE:
|
||||
"""Parse a residue string.
|
||||
|
||||
Args:
|
||||
@@ -189,6 +214,16 @@ def parse_res_string(res_str):
|
||||
return chain, resnum, inscode
|
||||
|
||||
|
||||
def parse_res_list(titrate_only: str):
|
||||
res_list: List[_T_RESIDUE_TUPLE] = []
|
||||
for res_str in titrate_only.split(','):
|
||||
try:
|
||||
res_list.append(parse_res_string(res_str))
|
||||
except ValueError as ex:
|
||||
raise argparse.ArgumentTypeError(f'{ex}: "{res_str:s}"')
|
||||
return res_list
|
||||
|
||||
|
||||
def build_parser(parser=None):
|
||||
"""Build an argument parser for PROPKA.
|
||||
|
||||
@@ -233,6 +268,7 @@ def build_parser(parser=None):
|
||||
'" " for chains without ID [all]'))
|
||||
group.add_argument(
|
||||
"-i", "--titrate_only", dest="titrate_only",
|
||||
type=parse_res_list,
|
||||
help=('Treat only the specified residues as titratable. Value should '
|
||||
'be a comma-separated list of "chain:resnum" values; for '
|
||||
'example: -i "A:10,A:11"'))
|
||||
@@ -252,8 +288,8 @@ def build_parser(parser=None):
|
||||
"--version", action="version", version=f"%(prog)s {propka.__version__}")
|
||||
group.add_argument(
|
||||
"-p", "--parameters", dest="parameters",
|
||||
default=str(Path(__file__).parent / "propka.cfg"),
|
||||
help="set the parameter file [{default:s}]")
|
||||
type=Path, default=Path(__file__).parent / "propka.cfg",
|
||||
help="set the parameter file")
|
||||
try:
|
||||
group.add_argument(
|
||||
"--log-level",
|
||||
@@ -325,18 +361,6 @@ def loadOptions(args=None) -> Options:
|
||||
|
||||
# adding specified filenames to arguments
|
||||
options.filenames.append(options.input_pdb)
|
||||
# Convert titrate_only string to a list of (chain, resnum) items:
|
||||
if options.titrate_only is not None:
|
||||
res_list = []
|
||||
for res_str in options.titrate_only.split(','):
|
||||
try:
|
||||
chain, resnum, inscode = parse_res_string(res_str)
|
||||
except ValueError:
|
||||
_LOGGER.critical(
|
||||
'Invalid residue string: "{0:s}"'.format(res_str))
|
||||
sys.exit(1)
|
||||
res_list.append((chain, resnum, inscode))
|
||||
options.titrate_only = res_list
|
||||
# Set the no-print variable
|
||||
level = getattr(logging, options.log_level)
|
||||
_LOGGER.setLevel(level)
|
||||
|
||||
@@ -157,7 +157,7 @@ class MolecularContainer:
|
||||
conformation='AVR', reference=reference)
|
||||
|
||||
def get_folding_profile(self, conformation='AVR', reference="neutral",
|
||||
grid=[0., 14., 0.1]):
|
||||
grid: Tuple[float, float, float] = (0., 14., 0.1)):
|
||||
"""Get a folding profile.
|
||||
|
||||
Args:
|
||||
@@ -174,25 +174,25 @@ class MolecularContainer:
|
||||
4. stability_range
|
||||
"""
|
||||
# calculate stability profile
|
||||
profile = []
|
||||
profile: List[Tuple[float, float]] = []
|
||||
for ph in make_grid(*grid):
|
||||
conf = self.conformations[conformation]
|
||||
ddg = conf.calculate_folding_energy(ph=ph, reference=reference)
|
||||
profile.append([ph, ddg])
|
||||
profile.append((ph, ddg))
|
||||
# find optimum
|
||||
opt = [None, 1e6]
|
||||
opt: Tuple[Optional[float], float] = (None, 1e6)
|
||||
for point in profile:
|
||||
opt = min(opt, point, key=lambda v: v[1])
|
||||
# find values within 80 % of optimum
|
||||
range_80pct = [None, None]
|
||||
range_80pct: Tuple[Optional[float], Optional[float]] = (None, None)
|
||||
values_within_80pct = [p[0] for p in profile if p[1] < 0.8*opt[1]]
|
||||
if len(values_within_80pct) > 0:
|
||||
range_80pct = [min(values_within_80pct), max(values_within_80pct)]
|
||||
range_80pct = (min(values_within_80pct), max(values_within_80pct))
|
||||
# find stability range
|
||||
stability_range = [None, None]
|
||||
stability_range: Tuple[Optional[float], Optional[float]] = (None, None)
|
||||
stable_values = [p[0] for p in profile if p[1] < 0.0]
|
||||
if len(stable_values) > 0:
|
||||
stability_range = [min(stable_values), max(stable_values)]
|
||||
stability_range = (min(stable_values), max(stable_values))
|
||||
return profile, opt, range_80pct, stability_range
|
||||
|
||||
def get_charge_profile(self, conformation: str = 'AVR', grid=[0., 14., .1]):
|
||||
|
||||
@@ -12,13 +12,29 @@ Output routines.
|
||||
import logging
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from os import PathLike
|
||||
from pathlib import Path
|
||||
from typing import IO, AnyStr, List, NoReturn, Optional, Union, TYPE_CHECKING
|
||||
import warnings
|
||||
|
||||
from .parameters import Parameters
|
||||
from . import __version__
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .atom import Atom
|
||||
from .conformation_container import ConformationContainer
|
||||
from .molecular_container import MolecularContainer
|
||||
|
||||
# https://docs.python.org/3/glossary.html#term-path-like-object
|
||||
_PathLikeTypes = (PathLike, str)
|
||||
_PathArg = Union[PathLike, str]
|
||||
_IOSource = Union[IO[AnyStr], PathLike, str]
|
||||
_TextIOSource = _IOSource[str]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def open_file_for_writing(input_file):
|
||||
def open_file_for_writing(input_file: _TextIOSource) -> IO[str]:
|
||||
"""Open file or file-like stream for writing.
|
||||
|
||||
TODO - convert this to a context manager.
|
||||
@@ -27,17 +43,13 @@ def open_file_for_writing(input_file):
|
||||
input_file: path to file or file-like object. If file-like object,
|
||||
then will attempt to get file mode.
|
||||
"""
|
||||
try:
|
||||
if isinstance(input_file, _PathLikeTypes):
|
||||
return open(input_file, 'wt')
|
||||
|
||||
if not input_file.writable():
|
||||
raise IOError("File/stream not open for writing")
|
||||
|
||||
return input_file
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
file_ = open(input_file, 'wt')
|
||||
except FileNotFoundError:
|
||||
raise Exception('Could not open {0:s}'.format(input_file))
|
||||
return file_
|
||||
|
||||
|
||||
def write_file(filename, lines):
|
||||
@@ -47,6 +59,7 @@ def write_file(filename, lines):
|
||||
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))
|
||||
@@ -101,17 +114,22 @@ def write_pdb_for_protein(
|
||||
pdbfile.close()
|
||||
|
||||
|
||||
def write_pdb_for_conformation(conformation, filename):
|
||||
def write_pdb_for_conformation(conformation: "ConformationContainer",
|
||||
filename: _PathArg):
|
||||
"""Write PDB conformation to a file.
|
||||
|
||||
Args:
|
||||
conformation: conformation container
|
||||
filename: filename for output
|
||||
"""
|
||||
warnings.warn("unused and untested by propka")
|
||||
write_pdb_for_atoms(conformation.atoms, filename)
|
||||
|
||||
|
||||
def write_pka(protein, parameters, filename=None, conformation='1A',
|
||||
def write_pka(protein: "MolecularContainer",
|
||||
parameters: Parameters,
|
||||
filename: Optional[_PathArg] = None,
|
||||
conformation='1A',
|
||||
reference="neutral", _="folding", verbose=False,
|
||||
__=None):
|
||||
"""Write the pKa-file based on the given protein.
|
||||
@@ -129,8 +147,6 @@ def write_pka(protein, parameters, filename=None, conformation='1A',
|
||||
verbose = True
|
||||
if filename is None:
|
||||
filename = "{0:s}.pka".format(protein.name)
|
||||
# TODO - this would be much better with a context manager
|
||||
file_ = open(filename, 'w')
|
||||
if verbose:
|
||||
_LOGGER.info("Writing {0:s}".format(filename))
|
||||
# writing propka header
|
||||
@@ -149,11 +165,10 @@ def write_pka(protein, parameters, filename=None, conformation='1A',
|
||||
# printing Protein Charge Profile
|
||||
str_ += get_charge_profile_section(protein, conformation=conformation)
|
||||
# now, writing the pka text to file
|
||||
file_.write(str_)
|
||||
file_.close()
|
||||
Path(filename).write_text(str_, encoding="utf-8")
|
||||
|
||||
|
||||
def print_tm_profile(protein, reference="neutral", window=[0., 14., 1.],
|
||||
def print_tm_profile(protein: NoReturn, reference="neutral", window=[0., 14., 1.],
|
||||
__=[0., 0.], tms=None, ref=None, _=False,
|
||||
options=None):
|
||||
"""Print Tm profile.
|
||||
@@ -186,7 +201,7 @@ def print_tm_profile(protein, reference="neutral", window=[0., 14., 1.],
|
||||
_LOGGER.info(str_)
|
||||
|
||||
|
||||
def print_result(protein, conformation, parameters):
|
||||
def print_result(protein: "MolecularContainer", conformation: str, parameters: Parameters):
|
||||
"""Prints all resulting output from determinants and down.
|
||||
|
||||
Args:
|
||||
@@ -197,7 +212,7 @@ def print_result(protein, conformation, parameters):
|
||||
print_pka_section(protein, conformation, parameters)
|
||||
|
||||
|
||||
def print_pka_section(protein, conformation, parameters):
|
||||
def print_pka_section(protein: "MolecularContainer", conformation: str, parameters: Parameters):
|
||||
"""Prints out pKa section of results.
|
||||
|
||||
Args:
|
||||
@@ -212,7 +227,7 @@ def print_pka_section(protein, conformation, parameters):
|
||||
_LOGGER.info("pKa summary:\n%s", str_)
|
||||
|
||||
|
||||
def get_determinant_section(protein, conformation, parameters):
|
||||
def get_determinant_section(protein: "MolecularContainer", conformation: str, parameters: Parameters):
|
||||
"""Returns string with determinant section of results.
|
||||
|
||||
Args:
|
||||
@@ -244,7 +259,8 @@ def get_determinant_section(protein, conformation, parameters):
|
||||
return str_
|
||||
|
||||
|
||||
def get_summary_section(protein, conformation, parameters):
|
||||
def get_summary_section(protein: "MolecularContainer", conformation: str,
|
||||
parameters: Parameters):
|
||||
"""Returns string with summary section of the results.
|
||||
|
||||
Args:
|
||||
@@ -266,7 +282,8 @@ def get_summary_section(protein, conformation, parameters):
|
||||
|
||||
|
||||
def get_folding_profile_section(
|
||||
protein, conformation='AVR', direction="folding", reference="neutral",
|
||||
protein: "MolecularContainer",
|
||||
conformation='AVR', direction="folding", reference="neutral",
|
||||
window=[0., 14., 1.0], _=False, __=None):
|
||||
"""Returns string with the folding profile section of the results.
|
||||
|
||||
@@ -373,6 +390,7 @@ def write_scwrl_sequence_file(sequence, filename="x-ray.seq", _=None):
|
||||
|
||||
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:
|
||||
@@ -536,7 +554,7 @@ def make_interaction_map(name, list_, interaction):
|
||||
return res
|
||||
|
||||
|
||||
def write_pdb_for_atoms(atoms, filename, make_conect_section=False):
|
||||
def write_pdb_for_atoms(atoms: List["Atom"], filename: _PathArg, make_conect_section=False):
|
||||
"""Write out PDB file for atoms.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -12,10 +12,12 @@ function. If similar functionality is desired from a Python script
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
from typing import IO, Iterable, Optional
|
||||
from propka.lib import loadOptions
|
||||
from propka.input import read_parameter_file, read_molecule_file
|
||||
from propka.parameters import Parameters
|
||||
from propka.molecular_container import MolecularContainer
|
||||
from propka.output import _PathArg
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -44,7 +46,9 @@ def main(optargs=None):
|
||||
my_molecule.write_pka()
|
||||
|
||||
|
||||
def single(filename: str, optargs: tuple = (), stream=None,
|
||||
def single(filename: _PathArg,
|
||||
optargs: Iterable[str] = (),
|
||||
stream: Optional[IO[str]] = None,
|
||||
write_pka: bool = True):
|
||||
"""Run a single PROPKA calculation using ``filename`` as input.
|
||||
|
||||
@@ -105,6 +109,7 @@ def single(filename: str, optargs: tuple = (), stream=None,
|
||||
.. versionchanged:: 3.4.0
|
||||
Removed ability to write out PROPKA input files.
|
||||
"""
|
||||
filename = str(filename)
|
||||
# Deal with input optarg options
|
||||
optargs = tuple(optargs)
|
||||
optargs += (filename,)
|
||||
|
||||
27
tests/test_lib.py
Normal file
27
tests/test_lib.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import propka.lib as m
|
||||
|
||||
import argparse
|
||||
import pytest
|
||||
|
||||
|
||||
def test_parse_res_string():
|
||||
assert m.parse_res_string("C:123") == ("C", 123, " ")
|
||||
assert m.parse_res_string("C:123B") == ("C", 123, "B")
|
||||
assert m.parse_res_string("ABC:123x") == ("ABC", 123, "x")
|
||||
with pytest.raises(ValueError):
|
||||
m.parse_res_string("C:B123")
|
||||
with pytest.raises(ValueError):
|
||||
m.parse_res_string("123B")
|
||||
with pytest.raises(ValueError):
|
||||
m.parse_res_string("C:123:B")
|
||||
|
||||
|
||||
def test_parse_res_list():
|
||||
assert m.parse_res_list("C:123") == [("C", 123, " ")]
|
||||
assert m.parse_res_list("ABC:123,D:4,F:56X") == [
|
||||
("ABC", 123, " "),
|
||||
("D", 4, " "),
|
||||
("F", 56, "X"),
|
||||
]
|
||||
with pytest.raises(argparse.ArgumentTypeError):
|
||||
m.parse_res_list("C:B123")
|
||||
Reference in New Issue
Block a user