From 9350799be122af9df631fcf1c3849014236dd3cf Mon Sep 17 00:00:00 2001 From: Nathan Baker Date: Sun, 29 Nov 2020 16:09:45 -0800 Subject: [PATCH] Remove logging abstraction to facilitate debugging and reduce bloat. Also performed minor delinting. Fixes #108 --- propka/bonds.py | 71 ++++++++++---------- propka/conformation_container.py | 36 ++++++----- propka/coupled_groups.py | 49 ++++++++------ propka/energy.py | 108 +++++++++++++++++++++---------- propka/group.py | 94 +++++++++++++++------------ propka/hydrogens.py | 19 +++--- propka/iterative.py | 25 ++++--- propka/lib.py | 84 +++++++----------------- propka/ligand_pka_values.py | 47 ++++++++------ propka/molecular_container.py | 10 +-- propka/output.py | 28 +++++--- propka/parameters.py | 71 ++++++++++++-------- propka/protonate.py | 84 ++++++++++++++---------- propka/run.py | 9 ++- propka/vector_algebra.py | 8 ++- propka/version.py | 24 +++++-- 16 files changed, 436 insertions(+), 331 deletions(-) diff --git a/propka/bonds.py b/propka/bonds.py index 67e795f..7c07f56 100644 --- a/propka/bonds.py +++ b/propka/bonds.py @@ -5,12 +5,14 @@ Bonds PROPKA representation of bonds. """ +import logging import math import json import pkg_resources import propka.calculations -# TODO - replace the info/warning imports with logging functionality -from propka.lib import info + + +_LOGGER = logging.getLogger(__name__) # TODO - should these constants be defined higher up in the module? @@ -30,8 +32,8 @@ class BondMaker: """ def __init__(self): # predefined bonding distances - self.distances = {'S-S' : DISULFIDE_DISTANCE, - 'F-F' : FLUORIDE_DISTANCE} + self.distances = {'S-S': DISULFIDE_DISTANCE, + 'F-F': FLUORIDE_DISTANCE} self.distances_squared = {} for key in self.distances: self.distances_squared[key] = ( @@ -53,22 +55,22 @@ class BondMaker: 'C': ['CA', 'O'], 'O': ['C']} self.num_pi_elec_bonds_backbone = {'C': 1, 'O': 1} self.num_pi_elec_conj_bonds_backbone = {'N': 1} - self.num_pi_elec_bonds_sidechains = {'ARG-CZ' : 1, 'ARG-NH1': 1, - 'ASN-OD1': 1, 'ASN-CG' : 1, - 'ASP-OD1': 1, 'ASP-CG' : 1, - 'GLU-OE1': 1, 'GLU-CD' : 1, - 'GLN-OE1': 1, 'GLN-CD' : 1, - 'HIS-CG' : 1, 'HIS-CD2': 1, + self.num_pi_elec_bonds_sidechains = {'ARG-CZ': 1, 'ARG-NH1': 1, + 'ASN-OD1': 1, 'ASN-CG': 1, + 'ASP-OD1': 1, 'ASP-CG': 1, + 'GLU-OE1': 1, 'GLU-CD': 1, + 'GLN-OE1': 1, 'GLN-CD': 1, + 'HIS-CG': 1, 'HIS-CD2': 1, 'HIS-ND1': 1, 'HIS-CE1': 1, - 'PHE-CG' : 1, 'PHE-CD1': 1, - 'PHE-CE1': 1, 'PHE-CZ' : 1, + 'PHE-CG': 1, 'PHE-CD1': 1, + 'PHE-CE1': 1, 'PHE-CZ': 1, 'PHE-CE2': 1, 'PHE-CD2': 1, - 'TRP-CG' : 1, 'TRP-CD1': 1, + 'TRP-CG': 1, 'TRP-CD1': 1, 'TRP-CE2': 1, 'TRP-CD2': 1, 'TRP-CE3': 1, 'TRP-CZ3': 1, 'TRP-CH2': 1, 'TRP-CZ2': 1, - 'TYR-CG' : 1, 'TYR-CD1': 1, - 'TYR-CE1': 1, 'TYR-CZ' : 1, + 'TYR-CG': 1, 'TYR-CD1': 1, + 'TYR-CE1': 1, 'TYR-CZ': 1, 'TYR-CE2': 1, 'TYR-CD2': 1} self.num_pi_elec_conj_bonds_sidechains = {'ARG-NE': 1, 'ARG-NH2': 1, 'ASN-ND2': 1, 'GLN-NE2': 1, @@ -90,13 +92,13 @@ class BondMaker: Args: protein: the protein to search for bonds """ - info('++++ Side chains ++++') + _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) - info('++++ Backbones ++++') + _LOGGER.info('++++ Backbones ++++') # backbone last_residues = [] for chain in protein.chains: @@ -108,11 +110,11 @@ class BondMaker: self.connect_backbone(chain.residues[i-1], chain.residues[i]) last_residues.append(chain.residues[i]) - info('++++ terminal oxygen ++++') + _LOGGER.info('++++ terminal oxygen ++++') # terminal OXT for last_residue in last_residues: self.find_bonds_for_terminal_oxygen(last_residue) - info('++++ cysteines ++++') + _LOGGER.info('++++ cysteines ++++') # Cysteines for chain in protein.chains: for i in range(0, len(chain.residues)): @@ -180,7 +182,7 @@ class BondMaker: self.num_pi_elec_bonds_backbone[atom1.name]) if atom1.name in ( list(self.num_pi_elec_conj_bonds_backbone.keys()) - and len(atom1.bonded_atoms) > 1): # avoid N-term + and len(atom1.bonded_atoms) > 1): # avoid N-term atom1.num_pi_elec_conj_2_3_bonds = ( self.num_pi_elec_conj_bonds_backbone[atom1.name]) @@ -204,8 +206,8 @@ class BondMaker: if key in list(self.num_pi_elec_conj_bonds_sidechains.keys()): atom1.num_pi_elec_conj_2_3_bonds = ( self.num_pi_elec_conj_bonds_sidechains[key]) - if not atom1.name in self.backbone_atoms: - if not atom1.name in self.terminal_oxygen_names: + if atom1.name not in self.backbone_atoms: + if atom1.name not in self.terminal_oxygen_names: for atom2 in atoms: if atom2.name in ( self @@ -266,7 +268,6 @@ class BondMaker: Returns: list of atoms """ - #self.find_bonds_for_protein(molecule) atoms = [] for chain in molecule.chains: for residue in chain.residues: @@ -424,9 +425,9 @@ class BondMaker: """ if atom1 == atom2: return - if not atom1 in atom2.bonded_atoms: + if atom1 not in atom2.bonded_atoms: atom2.bonded_atoms.append(atom1) - if not atom2 in atom1.bonded_atoms: + if atom2 not in atom1.bonded_atoms: atom1.bonded_atoms.append(atom2) def generate_protein_bond_dictionary(self, atoms): @@ -441,21 +442,21 @@ class BondMaker: name_i = atom.name resi_j = bonded_atom.res_name name_j = bonded_atom.name - if not name_i in ( + if name_i not in ( self.backbone_atoms - or not name_j in self.backbone_atoms): - if not name_i in ( + or name_j not in self.backbone_atoms): + if name_i not in ( self.terminal_oxygen_names - and not name_j in self.terminal_oxygen_names): - if not resi_i in list(self.protein_bonds.keys()): + 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 not name_i in self.protein_bonds[resi_i]: + if name_i not in self.protein_bonds[resi_i]: self.protein_bonds[resi_i][name_i] = [] - if not name_j in 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 not resi_j in list(self.protein_bonds.keys()): + if resi_j not in list(self.protein_bonds.keys()): self.protein_bonds[resi_j] = {} - if not name_j in self.protein_bonds[resi_j]: + if name_j not in self.protein_bonds[resi_j]: self.protein_bonds[resi_j][name_j] = [] - if not name_i in 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) diff --git a/propka/conformation_container.py b/propka/conformation_container.py index e387f6a..2da0292 100644 --- a/propka/conformation_container.py +++ b/propka/conformation_container.py @@ -4,6 +4,7 @@ Molecular data structures Container data structure for molecular conformations. """ +import logging import functools import propka.ligand from propka.output import make_interaction_map @@ -12,11 +13,14 @@ from propka.coupled_groups import NCCG from propka.determinants import set_backbone_determinants, set_ion_determinants from propka.determinants import set_determinants from propka.group import Group, is_group -from propka.lib import info + + +_LOGGER = logging.getLogger(__name__) #: 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 sorting. +#: :func:`ord` to the atom chain ID. Used in calculating atom keys for +#: sorting. UNICODE_MULTIPLIER = 1e7 #: A number that gets mutiplied with an atom's residue number. Used in @@ -54,7 +58,8 @@ class ConformationContainer: else: group = atom.group # if the atom has been checked in a another conformation, check - # if it has a group that should be used in this conformation as well + # if it has a group that should be used in this conformation + # as well if group: self.setup_and_add_group(group) @@ -66,7 +71,7 @@ class ConformationContainer: 'Covalent coupling map for {0:s}'.format(str(self)), self.get_covalently_coupled_groups(), lambda g1, g2: g1 in g2.covalently_coupled_groups) - info(map_) + _LOGGER.info(map_) # check if we should set a common charge centre as well if self.parameters.common_charge_centre: self.set_common_charge_centres() @@ -108,7 +113,7 @@ class ConformationContainer: 'Covalent coupling map for {0:s}'.format(str(self)), self.get_covalently_coupled_groups(), lambda g1, g2: g1 in g2.covalently_coupled_groups) - info(map_) + _LOGGER.info("Coupling map:\n%s", map_) def find_non_covalently_coupled_groups(self, verbose=False): """Find non-covalently coupled groups and set common charge centres. @@ -116,7 +121,8 @@ class ConformationContainer: Args: verbose: verbose output """ - # check if non-covalent coupling has already been set up in an input file + # check if non-covalent coupling has already been set up in an input + # file if len(list(filter(lambda g: len(g.non_covalently_coupled_groups) > 0, self.get_titratable_groups()))) > 0: self.non_covalently_coupled_groups = True @@ -193,7 +199,7 @@ class ConformationContainer: version: version object options: option object """ - info('\nCalculating pKas for', self) + _LOGGER.info('Calculating pKas for %s', self) # calculate desolvation for group in self.get_titratable_groups() + self.get_ions(): version.calculate_desolvation(group) @@ -215,7 +221,7 @@ class ConformationContainer: penalised_labels = self.coupling_effects() if (self.parameters.remove_penalised_group and len(penalised_labels) > 0): - info('Removing penalised groups!!!') + _LOGGER.info('Removing penalised groups!!!') for group in self.get_titratable_groups(): group.remove_determinants(penalised_labels) # re-calculating the total pKa values @@ -257,7 +263,7 @@ class ConformationContainer: # group with the highest pKa is allowed to titrate... continue group.coupled_titrating_group = first_group - #... and the rest are penalised + # ... and the rest are penalised penalised_labels.append(group.label) return penalised_labels @@ -282,7 +288,7 @@ class ConformationContainer: max_dets[det.group] = max(det.value, max_dets[det.group], key=lambda v: abs(v)) - # overwrite/add maximum value for each determinant + # overwrite/add maximum value for each determinant for det_group in max_dets: new_determinant = Determinant(det_group, max_dets[det_group]) for group in groups: @@ -433,9 +439,9 @@ class ConformationContainer: def get_groups_for_calculations(self): """Get a list of groups that should be included in results report. - If --titrate_only option is specified, only residues that are titratable - and are in that list are included; otherwise all titratable residues - and CYS residues are included. + If --titrate_only option is specified, only residues that are + titratable and are in that list are included; otherwise all titratable + residues and CYS residues are included. Returns: list of groups @@ -525,7 +531,7 @@ class ConformationContainer: if not atom.molecular_container: atom.molecular_container = self.molecular_container # store chain id for bookkeeping - if not atom.chain_id in self.chains: + if atom.chain_id not in self.chains: self.chains.append(atom.chain_id) def copy_atom(self, atom): @@ -556,7 +562,7 @@ class ConformationContainer: """ my_residue_labels = {a.residue_label for a in self.atoms} for atom in other.atoms: - if not atom.residue_label in my_residue_labels: + if atom.residue_label not in my_residue_labels: self.copy_atom(atom) def find_group(self, group): diff --git a/propka/coupled_groups.py b/propka/coupled_groups.py index 2b80861..f6c9ebf 100644 --- a/propka/coupled_groups.py +++ b/propka/coupled_groups.py @@ -4,12 +4,14 @@ Coupling between groups Describe and analyze energetic coupling between groups. """ - +import logging import itertools import propka.lib from propka.group import Group from propka.output import make_interaction_map -from propka.lib import info + + +_LOGGER = logging.getLogger(__name__) class NonCovalentlyCoupledGroups: @@ -37,7 +39,7 @@ class NonCovalentlyCoupledGroups: if (interaction_energy <= self.parameters.min_interaction_energy and return_on_fail): return {'coupling_factor': -1.0} - # calculate intrinsic pKa's, if not already done + # calculate intrinsic pKa's, if not already done for group in [group1, group2]: if group.intrinsic_pka is None: group.calculate_intrinsic_pka() @@ -80,7 +82,8 @@ class NonCovalentlyCoupledGroups: if (abs(group1.intrinsic_pka - group2.intrinsic_pka) > self.parameters.max_intrinsic_pka_diff and return_on_fail): return {'coupling_factor': -1.0} - # if everything is OK, calculate the coupling factor and return all info + # if everything is OK, calculate the coupling factor and return all + # info factor = ( self.get_free_energy_diff_factor(default_energy, swapped_energy) * self.get_pka_diff_factor(group1.intrinsic_pka, @@ -107,7 +110,7 @@ class NonCovalentlyCoupledGroups: if intrinsic_pka_diff <= self.parameters.max_intrinsic_pka_diff: res = ( 1-(intrinsic_pka_diff - /self.parameters.max_intrinsic_pka_diff)**2) + / self.parameters.max_intrinsic_pka_diff)**2) return res def get_free_energy_diff_factor(self, energy1, energy2): @@ -139,7 +142,7 @@ class NonCovalentlyCoupledGroups: res = ( (interaction_energy-self.parameters.min_interaction_energy) / (1.0+interaction_energy - -self.parameters.min_interaction_energy)) + - self.parameters.min_interaction_energy)) return res def identify_non_covalently_coupled_groups(self, conformation, @@ -162,17 +165,25 @@ class NonCovalentlyCoupledGroups: '\n' ' Detecting non-covalently coupled residues\n' '{sep}\n' - ' Maximum pKa difference: {c.max_intrinsic_pka_diff:>4.2f} pKa units\n' - ' Minimum interaction energy: {c.min_interaction_energy:>4.2f} pKa units\n' - ' Maximum free energy diff.: {c.max_free_energy_diff:>4.2f} pKa units\n' - ' Minimum swap pKa shift: {c.min_swap_pka_shift:>4.2f} pKa units\n' - ' pH: {c.pH:>6} \n' - ' Reference: {c.reference}\n' - ' Min pKa: {c.min_pka:>4.2f}\n' - ' Max pKa: {c.max_pka:>4.2f}\n' + ' Maximum pKa difference: ' + '{c.max_intrinsic_pka_diff:>4.2f} pKa units\n' + ' Minimum interaction energy: ' + '{c.min_interaction_energy:>4.2f} pKa units\n' + ' Maximum free energy diff.: ' + '{c.max_free_energy_diff:>4.2f} pKa units\n' + ' Minimum swap pKa shift: ' + '{c.min_swap_pka_shift:>4.2f} pKa units\n' + ' pH: ' + '{c.pH:>6} \n' + ' Reference: ' + '{c.reference}\n' + ' Min pKa: ' + '{c.min_pka:>4.2f}\n' + ' Max pKa: ' + '{c.max_pka:>4.2f}\n' '\n') sep = "-" * 103 - info(info_fmt.format(sep=sep, c=self)) + _LOGGER.info(info_fmt.format(sep=sep, c=self)) # find coupled residues titratable_groups = conformation.get_titratable_groups() if not conformation.non_covalently_coupled_groups: @@ -202,7 +213,7 @@ class NonCovalentlyCoupledGroups: 'Non-covalent coupling map for {0:s}'.format(str(conformation)), conformation.get_non_covalently_coupled_groups(), lambda g1, g2: g1 in g2.non_covalently_coupled_groups) - info(map_) + _LOGGER.info(map_) for system in conformation.get_coupled_systems( conformation.get_non_covalently_coupled_groups(), Group.get_non_covalently_coupled_groups): @@ -215,7 +226,7 @@ class NonCovalentlyCoupledGroups: conformation: conformation to print system: system to print """ - info( + _LOGGER.info( 'System containing {0:d} groups:'.format(len(system))) # make list of interactions within this system interactions = list(itertools.combinations(system, 2)) @@ -230,7 +241,7 @@ class NonCovalentlyCoupledGroups: coup_info += ( self.make_data_to_string(data, interaction[0], interaction[1]) + '\n\n') - info(coup_info) + _LOGGER.info(coup_info) # make list of possible combinations of swap to try out combinations = propka.lib.generate_combinations(interactions) # Make possible swap combinations @@ -246,7 +257,7 @@ class NonCovalentlyCoupledGroups: for interaction in combination: self.swap_interactions([interaction[0]], [interaction[1]]) swap_info += self.print_determinants_section(system, 'Swapped') - info(swap_info) + _LOGGER.info(swap_info) @staticmethod def get_interaction(group1, group2, include_side_chain_hbs=True): diff --git a/propka/energy.py b/propka/energy.py index 6a1bc96..af18f8c 100644 --- a/propka/energy.py +++ b/propka/energy.py @@ -6,10 +6,13 @@ Energy calculations. """ import math -from propka.lib import warning +import logging from propka.calculations import squared_distance, get_smallest_distance +_LOGGER = logging.getLogger(__name__) + + # TODO - I have no idea what these constants mean so I labeled them "UNK_" UNK_MIN_DISTANCE = 2.75 MIN_DISTANCE_4TH = math.pow(UNK_MIN_DISTANCE, 4) @@ -72,7 +75,10 @@ def calculate_scale_factor(parameters, weight): Returns: scaling factor """ - scale_factor = 1.0 - (1.0 - parameters.desolvationSurfaceScalingFactor)*(1.0 - weight) + scale_factor = ( + 1.0 - (1.0 - parameters.desolvationSurfaceScalingFactor) + * (1.0 - weight) + ) return scale_factor @@ -83,7 +89,8 @@ def calculate_weight(parameters, num_volume): Args: parameters: parameters for desolvation calculation - num_volume: number of heavy atoms within desolvation calculation volume + num_volume: number of heavy atoms within desolvation calculation + volume Returns: desolvation weight """ @@ -135,12 +142,14 @@ def hydrogen_bond_energy(dist, dpka_max, cutoffs, f_angle=1.0): def angle_distance_factors(atom1=None, atom2=None, atom3=None, center=None): - """Calculate distance and angle factors for three atoms for backbone interactions. + """Calculate distance and angle factors for three atoms for backbone + interactions. - NOTE - you need to use atom1 to be the e.g. ASP atom if distance is reset at - return: [O1 -- H2-N3]. + NOTE - you need to use atom1 to be the e.g. ASP atom if distance is reset + at return: [O1 -- H2-N3]. - Also generalized to be able to be used for residue 'centers' for C=O COO interactions. + Also generalized to be able to be used for residue 'centers' for C=O COO + interactions. Args: atom1: first atom for calculation (could be None) @@ -194,9 +203,11 @@ def hydrogen_bond_interaction(group1, group2, version): # find the smallest distance between interacting atoms atoms1 = group1.get_interaction_atoms(group2) atoms2 = group2.get_interaction_atoms(group1) - [closest_atom1, dist, closest_atom2] = get_smallest_distance(atoms1, atoms2) + [closest_atom1, dist, closest_atom2] = get_smallest_distance( + atoms1, atoms2 + ) if None in [closest_atom1, closest_atom2]: - warning( + _LOGGER.warning( 'Side chain interaction failed for {0:s} and {1:s}'.format( group1.label, group2.label)) return None @@ -210,11 +221,16 @@ def hydrogen_bond_interaction(group1, group2, version): return None # check that bond distance criteria is met min_hbond_dist = version.parameters.min_bond_distance_for_hydrogen_bonds - if group1.atom.is_atom_within_bond_distance(group2.atom, min_hbond_dist, 1): + if group1.atom.is_atom_within_bond_distance( + group2.atom, min_hbond_dist, 1 + ): return None # set angle factor f_angle = 1.0 - if group2.type in version.parameters.angular_dependent_sidechain_interactions: + if ( + group2.type in + version.parameters.angular_dependent_sidechain_interactions + ): if closest_atom2.element == 'H': heavy_atom = closest_atom2.bonded_atoms[0] hydrogen = closest_atom2 @@ -225,7 +241,10 @@ def hydrogen_bond_interaction(group1, group2, version): # is closer to the titratable atom than the hydrogen. In either # case, we set the angle factor to 0 f_angle = 0.0 - elif group1.type in version.parameters.angular_dependent_sidechain_interactions: + elif ( + group1.type in + version.parameters.angular_dependent_sidechain_interactions + ): if closest_atom1.element == 'H': heavy_atom = closest_atom1.bonded_atoms[0] hydrogen = closest_atom1 @@ -236,7 +255,9 @@ def hydrogen_bond_interaction(group1, group2, version): # is closer to the titratable atom than the hydrogen. In either # case, we set the angle factor to 0 f_angle = 0.0 - weight = version.calculate_pair_weight(group1.num_volume, group2.num_volume) + weight = version.calculate_pair_weight( + group1.num_volume, group2.num_volume + ) exception, value = version.check_exceptions(group1, group2) if exception: # Do nothing, value should have been assigned. @@ -256,12 +277,15 @@ def electrostatic_interaction(group1, group2, dist, version): dist: distance between groups version: version-specific object with parameters and functions Returns: - electrostatic interaction energy or None (if no interaction is appropriate) + electrostatic interaction energy or None (if no interaction is + appropriate) """ # check if we should do coulomb interaction at all if not version.check_coulomb_pair(group1, group2, dist): return None - weight = version.calculate_pair_weight(group1.num_volume, group2.num_volume) + weight = version.calculate_pair_weight( + group1.num_volume, group2.num_volume + ) value = version.calculate_coulomb_energy(dist, weight) return value @@ -334,7 +358,9 @@ def backbone_reorganization(_, conformation): weight = titratable_group.buried dpka = 0.00 for bbc_group in bbc_groups: - center = [titratable_group.x, titratable_group.y, titratable_group.z] + center = [ + titratable_group.x, titratable_group.y, titratable_group.z + ] atom2 = bbc_group.get_interaction_atoms(titratable_group)[0] dist, f_angle, _ = angle_distance_factors(atom2=atom2, atom3=bbc_group.atom, @@ -359,7 +385,8 @@ def check_exceptions(version, group1, group2): group2: second group for check Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ res_type1 = group1.type res_type2 = group2.type @@ -398,7 +425,8 @@ def check_coo_arg_exception(group_coo, group_arg, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = True value_tot = 0.00 @@ -409,13 +437,18 @@ def check_coo_arg_exception(group_coo, group_arg, version): atoms_arg.extend(group_arg.get_interaction_atoms(group_coo)) for _ in ["shortest", "runner-up"]: # find the closest interaction pair - [closest_coo_atom, dist, closest_arg_atom] = get_smallest_distance(atoms_coo, - atoms_arg) - [dpka_max, cutoff] = version.get_hydrogen_bond_parameters(closest_coo_atom, - closest_arg_atom) + [closest_coo_atom, dist, closest_arg_atom] = get_smallest_distance( + atoms_coo, atoms_arg + ) + [dpka_max, cutoff] = version.get_hydrogen_bond_parameters( + closest_coo_atom, closest_arg_atom + ) # calculate and sum up interaction energy f_angle = 1.00 - if group_arg.type in version.parameters.angular_dependent_sidechain_interactions: + if ( + group_arg.type in + version.parameters.angular_dependent_sidechain_interactions + ): atom3 = closest_arg_atom.bonded_atoms[0] dist, f_angle, _ = angle_distance_factors(closest_coo_atom, closest_arg_atom, @@ -437,18 +470,23 @@ def check_coo_coo_exception(group1, group2, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = True interact_groups12 = group1.get_interaction_atoms(group2) interact_groups21 = group2.get_interaction_atoms(group1) - [closest_atom1, dist, closest_atom2] = get_smallest_distance(interact_groups12, - interact_groups21) - [dpka_max, cutoff] = version.get_hydrogen_bond_parameters(closest_atom1, - closest_atom2) + [closest_atom1, dist, closest_atom2] = get_smallest_distance( + interact_groups12, interact_groups21 + ) + [dpka_max, cutoff] = version.get_hydrogen_bond_parameters( + closest_atom1, closest_atom2 + ) f_angle = 1.00 value = hydrogen_bond_energy(dist, dpka_max, cutoff, f_angle) - weight = calculate_pair_weight(version.parameters, group1.num_volume, group2.num_volume) + weight = calculate_pair_weight( + version.parameters, group1.num_volume, group2.num_volume + ) value = value * (1.0 + weight) return exception, value @@ -462,7 +500,8 @@ def check_coo_his_exception(group1, group2, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = False if check_buried(group1.num_volume, group2.num_volume): @@ -479,7 +518,8 @@ def check_oco_his_exception(group1, group2, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = False if check_buried(group1.num_volume, group2.num_volume): @@ -496,7 +536,8 @@ def check_cys_his_exception(group1, group2, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = False if check_buried(group1.num_volume, group2.num_volume): @@ -513,7 +554,8 @@ def check_cys_cys_exception(group1, group2, version): version: version object Returns: 1. Boolean indicating atypical behavior, - 2. value associated with atypical interaction (None if Boolean is False) + 2. value associated with atypical interaction (None if Boolean is + False) """ exception = False if check_buried(group1.num_volume, group2.num_volume): diff --git a/propka/group.py b/propka/group.py index 17af7e3..5d63452 100644 --- a/propka/group.py +++ b/propka/group.py @@ -4,12 +4,15 @@ Data structures for groups Routines and classes for storing groups important to PROPKA calculations. """ +import logging import math import propka.ligand import propka.protonate from propka.ligand_pka_values import LigandPkaValues from propka.determinant import Determinant -from propka.lib import info, warning + + +_LOGGER = logging.getLogger(__name__) # Constants that start with "UNK_" are a mystery to me @@ -20,7 +23,7 @@ EXPECTED_ATOMS_ACID_INTERACTIONS = { 'COO': {'O': 2}, 'HIS': {'H': 2, 'N': 2}, 'CYS': {'S': 1}, 'TYR': {'O': 1}, 'LYS': {'N': 1}, 'ARG': {'H': 5, 'N': 3}, 'ROH': {'O': 1}, 'AMD': {'H': 2, 'N': 1}, 'TRP': {'H': 1, 'N': 1}, 'N+': {'N': 1}, - 'C-': {'O': 2}, 'BBN': {'H': 1, 'N': 1,}, 'BBC': {'O': 1}, + 'C-': {'O': 2}, 'BBN': {'H': 1, 'N': 1}, 'BBC': {'O': 1}, 'NAR': {'H': 1, 'N': 1}, 'NAM': {'H': 1, 'N': 1}, 'F': {'F': 1}, 'Cl': {'Cl': 1}, 'OH': {'H': 1, 'O': 1}, 'OP': {'O': 1}, 'O3': {'O': 1}, 'O2': {'O': 1}, 'SH': {'S': 1}, 'CG': {'H': 5, 'N': 3}, @@ -106,9 +109,9 @@ class Group: other: other group for coupling """ # do the coupling - if not other in self.covalently_coupled_groups: + if other not in self.covalently_coupled_groups: self.covalently_coupled_groups.append(other) - if not self in other.covalently_coupled_groups: + if self not in other.covalently_coupled_groups: other.covalently_coupled_groups.append(self) def couple_non_covalently(self, other): @@ -118,9 +121,9 @@ class Group: other: other group for coupling """ # do the coupling - if not other in self.non_covalently_coupled_groups: + if other not in self.non_covalently_coupled_groups: self.non_covalently_coupled_groups.append(other) - if not self in other.non_covalently_coupled_groups: + if self not in other.non_covalently_coupled_groups: other.non_covalently_coupled_groups.append(self) def get_covalently_coupled_groups(self): @@ -399,26 +402,26 @@ class Group: str_ = 'Missing atoms or failed protonation for ' str_ += '{0:s} ({1:s}) -- please check the structure'.format( self.label, self.type) - warning(str_) - warning('{0:s}'.format(str(self))) + _LOGGER.warning(str_) + _LOGGER.warning('{0:s}'.format(str(self))) num_acid = sum( [EXPECTED_ATOMS_ACID_INTERACTIONS[self.type][e] for e in EXPECTED_ATOMS_ACID_INTERACTIONS[self.type].keys()]) num_base = sum( [EXPECTED_ATOMS_BASE_INTERACTIONS[self.type][e] for e in EXPECTED_ATOMS_BASE_INTERACTIONS[self.type].keys()]) - warning( + _LOGGER.warning( 'Expected {0:d} interaction atoms for acids, found:'.format( num_acid)) for i in range(len(self.interaction_atoms_for_acids)): - warning( + _LOGGER.warning( ' {0:s}'.format( str(self.interaction_atoms_for_acids[i]))) - warning( + _LOGGER.warning( 'Expected {0:d} interaction atoms for bases, found:'.format( num_base)) for i in range(len(self.interaction_atoms_for_bases)): - warning( + _LOGGER.warning( ' {0:s}'.format( str(self.interaction_atoms_for_bases[i]))) @@ -672,7 +675,9 @@ class HISGroup(Group): # Find the atoms in the histidine ring ring_atoms = propka.ligand.is_ring_member(self.atom) if len(ring_atoms) != 5: - warning('His group does not seem to contain a ring', self) + _LOGGER.warning( + 'His group does not seem to contain a ring %s', self + ) # protonate ring for ring_atom in ring_atoms: PROTONATOR.protonate_atom(ring_atom) @@ -682,7 +687,8 @@ class HISGroup(Group): else: # Missing side-chain atoms self.set_center([self.atom]) - # TODO - perhaps it would be better to ignore this group completely? + # TODO - perhaps it would be better to ignore this group + # completely? # find the hydrogens on the ring-nitrogens hydrogens = [] nitrogens = [ra for ra in ring_atoms if ra.element == 'N'] @@ -815,7 +821,7 @@ class CtermGroup(Group): the_other_oxygen = the_carbons[0].get_bonded_elements('O') the_other_oxygen.remove(self.atom) # set the center and interaction atoms - the_oxygens = [self.atom]+ the_other_oxygen + the_oxygens = [self.atom] + the_other_oxygen self.set_center(the_oxygens) self.set_interaction_atoms(the_oxygens, the_oxygens) @@ -866,7 +872,7 @@ class NARGroup(Group): Group.__init__(self, atom) self.type = 'NAR' self.residue_type = 'NAR' - info('Found NAR group:', atom) + _LOGGER.info('Found NAR group: %s', atom) def setup_atoms(self): """Set up atoms in group.""" @@ -889,7 +895,7 @@ class NAMGroup(Group): Group.__init__(self, atom) self.type = 'NAM' self.residue_type = 'NAM' - info('Found NAM group:', atom) + _LOGGER.info('Found NAM group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -909,7 +915,7 @@ class FGroup(Group): Group.__init__(self, atom) self.type = 'F' self.residue_type = 'F' - info('Found F group:', atom) + _LOGGER.info('Found F group: %s', atom) class ClGroup(Group): @@ -919,7 +925,7 @@ class ClGroup(Group): Group.__init__(self, atom) self.type = 'Cl' self.residue_type = 'Cl' - info('Found Cl group:', atom) + _LOGGER.info('Found Cl group: %s', atom) class OHGroup(Group): @@ -929,7 +935,7 @@ class OHGroup(Group): Group.__init__(self, atom) self.type = 'OH' self.residue_type = 'OH' - info('Found OH group:', atom) + _LOGGER.info('Found OH group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -949,7 +955,7 @@ class OPGroup(Group): Group.__init__(self, atom) self.type = 'OP' self.residue_type = 'OP' - info('Found OP group:', atom) + _LOGGER.info('Found OP group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -970,7 +976,7 @@ class O3Group(Group): Group.__init__(self, atom) self.type = 'O3' self.residue_type = 'O3' - info('Found O3 group:', atom) + _LOGGER.info('Found O3 group: %s', atom) class O2Group(Group): @@ -983,7 +989,7 @@ class O2Group(Group): Group.__init__(self, atom) self.type = 'O2' self.residue_type = 'O2' - info('Found O2 group:', atom) + _LOGGER.info('Found O2 group: %s', atom) class SHGroup(Group): @@ -993,7 +999,7 @@ class SHGroup(Group): Group.__init__(self, atom) self.type = 'SH' self.residue_type = 'SH' - info('Found SH group:', atom) + _LOGGER.info('Found SH group: %s', atom) class CGGroup(Group): @@ -1003,7 +1009,7 @@ class CGGroup(Group): Group.__init__(self, atom) self.type = 'CG' self.residue_type = 'CG' - info('Found CG group:', atom) + _LOGGER.info('Found CG group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1026,7 +1032,7 @@ class C2NGroup(Group): Group.__init__(self, atom) self.type = 'C2N' self.residue_type = 'C2N' - info('Found C2N group:', atom) + _LOGGER.info('Found C2N group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1050,7 +1056,7 @@ class OCOGroup(Group): Group.__init__(self, atom) self.type = 'OCO' self.residue_type = 'OCO' - info('Found OCO group:', atom) + _LOGGER.info('Found OCO group: %s', atom) def setup_atoms(self): """Set up atoms in group.""" @@ -1071,7 +1077,7 @@ class N30Group(Group): Group.__init__(self, atom) self.type = 'N30' self.residue_type = 'N30' - info('Found N30 group:', atom) + _LOGGER.info('Found N30 group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1093,7 +1099,7 @@ class N31Group(Group): Group.__init__(self, atom) self.type = 'N31' self.residue_type = 'N31' - info('Found N31 group:', atom) + _LOGGER.info('Found N31 group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1115,7 +1121,7 @@ class N32Group(Group): Group.__init__(self, atom) self.type = 'N32' self.residue_type = 'N32' - info('Found N32 group:', atom) + _LOGGER.info('Found N32 group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1137,7 +1143,7 @@ class N33Group(Group): Group.__init__(self, atom) self.type = 'N33' self.residue_type = 'N33' - info('Found N33 group:', atom) + _LOGGER.info('Found N33 group: %s', atom) def setup_atoms(self): """Set up atoms in this group.""" @@ -1159,7 +1165,7 @@ class NP1Group(Group): Group.__init__(self, atom) self.type = 'NP1' self.residue_type = 'NP1' - info('Found NP1 group:', atom) + _LOGGER.info('Found NP1 group: %s', atom) def setup_atoms(self): """Set up atoms in group.""" @@ -1181,7 +1187,7 @@ class N1Group(Group): Group.__init__(self, atom) self.type = 'N1' self.residue_type = 'N1' - info('Found N1 group:', atom) + _LOGGER.info('Found N1 group: %s', atom) class IonGroup(Group): @@ -1191,7 +1197,7 @@ class IonGroup(Group): Group.__init__(self, atom) self.type = 'ION' self.residue_type = atom.res_name.strip() - info('Found ion group:', atom) + _LOGGER.info('Found ion group: %s', atom) class NonTitratableLigandGroup(Group): @@ -1223,8 +1229,10 @@ class TitratableLigandGroup(Group): # this is not true if we are reading an input file if atom.marvin_pka: self.model_pka = atom.marvin_pka - info('Titratable ligand group ', - atom, self.model_pka, self.charge) + _LOGGER.info( + 'Titratable ligand group %s %s %s', + atom, self.model_pka, self.charge + ) self.model_pka_set = True @@ -1273,12 +1281,12 @@ def is_protein_group(parameters, atom): """ if atom.type != 'atom': return None - ### Check for termial groups + # Check for termial groups if atom.terminal == 'N+': return NtermGroup(atom) elif atom.terminal == 'C-': return CtermGroup(atom) - ### Backbone + # Backbone if atom.type == 'atom' and atom.name == 'N': # ignore proline backbone nitrogens if atom.res_name != 'PRO': @@ -1287,7 +1295,7 @@ def is_protein_group(parameters, atom): # ignore C- carboxyl if atom.count_bonded_elements('O') == 1: return BBCGroup(atom) - ### Filters for side chains based on PDB protein atom names + # Filters for side chains based on PDB protein atom names key = '{0:s}-{1:s}'.format(atom.res_name, atom.name) if key in parameters.protein_group_mapping.keys(): class_str = "{0:s}Group".format(parameters.protein_group_mapping[key]) @@ -1305,7 +1313,7 @@ def is_ligand_group_by_groups(_, atom): Returns: group for atom or None """ - ### Ligand group filters + # Ligand group filters if atom.type != 'hetatm': return None PROTONATOR.protonate_atom(atom) @@ -1327,7 +1335,8 @@ def is_ligand_group_by_groups(_, atom): if atom.sybyl_type == 'N.1': return N1Group(atom) if atom.sybyl_type == 'N.pl3': - # make sure that this atom is not part of a guadinium or amidinium group + # make sure that this atom is not part of a guadinium or amidinium + # group bonded_carbons = atom.get_bonded_elements('C') if len(bonded_carbons) == 1: bonded_nitrogens = bonded_carbons[0].get_bonded_elements('N') @@ -1426,13 +1435,14 @@ def is_ion_group(parameters, atom): return IonGroup(atom) return None + def initialize_atom_group(atom): """Initialize an atom group. Args: atom: atom to initialize """ - # try to initialise the group + # try to initialise the group group_attr = globals()[atom.group_label] atom.group = group_attr(atom) atom.group.model_pka = atom.group_model_pka diff --git a/propka/hydrogens.py b/propka/hydrogens.py index f2e00ed..c1f0bdf 100644 --- a/propka/hydrogens.py +++ b/propka/hydrogens.py @@ -6,12 +6,14 @@ Calculations related to hydrogen placement. """ import math -from propka.lib import info +import logging from propka.protonate import Protonate from propka.bonds import BondMaker from propka.atom import Atom +_LOGGER = logging.getLogger(__name__) + def setup_bonding_and_protonation(molecular_container): """Set up bonding and protonation for a molecule. @@ -68,7 +70,7 @@ def protonate_30_style(molecular_container): molecular_container: molecule """ for name in molecular_container.conformation_names: - info('Now protonating', name) + _LOGGER.info('Now protonating %s', name) # split atom into residues curres = -1000000 residue = [] @@ -78,19 +80,19 @@ def protonate_30_style(molecular_container): if atom.res_num != curres: curres = atom.res_num if len(residue) > 0: - #backbone + # backbone [o_atom, c_atom] = add_backbone_hydrogen( residue, o_atom, c_atom) - #arginine + # arginine if residue[0].res_name == 'ARG': add_arg_hydrogen(residue) - #histidine + # histidine if residue[0].res_name == 'HIS': add_his_hydrogen(residue) - #tryptophan + # tryptophan if residue[0].res_name == 'TRP': add_trp_hydrogen(residue) - #amides + # amides if residue[0].res_name in ['GLN', 'ASN']: add_amd_hydrogen(residue) residue = [] @@ -116,7 +118,6 @@ def add_arg_hydrogen(residue): Returns: list of hydrogen atoms """ - #info('Adding arg H',residue) for atom in residue: if atom.name == "CD": cd_atom = atom @@ -348,5 +349,3 @@ def make_new_h(atom, x, y, z): atom.bonded_atoms.append(new_h) atom.conformation_container.add_atom(new_h) return new_h - - diff --git a/propka/iterative.py b/propka/iterative.py index b8eefdb..febdf31 100644 --- a/propka/iterative.py +++ b/propka/iterative.py @@ -6,8 +6,11 @@ Iterative functions for pKa calculations. These appear to mostly involve :class:`propka.determinant.Determinant` instances. """ +import logging from propka.determinant import Determinant -from propka.lib import info, debug + + +_LOGGER = logging.getLogger(__name__) # TODO - these are undocumented constants @@ -215,9 +218,12 @@ def add_determinants(iterative_interactions, version, _=None): iteratives.append(new_iterative) done_group.append(group) # Initialize iterative scheme - debug( - "\n --- pKa iterations ({0:d} groups, {1:d} interactions) ---".format( - len(iteratives), len(iterative_interactions))) + _LOGGER.debug( + "\n --- pKa iterations ({0:d} groups, {1:d} interactions) " + "---".format( + len(iteratives), len(iterative_interactions) + ) + ) converged = False iteration = 0 # set non-iterative pka values as first step @@ -237,7 +243,7 @@ def add_determinants(iterative_interactions, version, _=None): object1, object2 = find_iterative(pair, iteratives) q1 = object1.q q2 = object2.q - if q1 < 0.0 and q2 < 0.0: + if q1 < 0.0 and q2 < 0.0: # both are acids add_iterative_acid_pair(object1, object2, interaction) elif q1 > 0.0 and q2 > 0.0: @@ -267,26 +273,27 @@ def add_determinants(iterative_interactions, version, _=None): itres.pka_iter.append(itres.pka_new) if iteration == 10: - info("did not converge in {0:d} iterations".format(iteration)) + _LOGGER.info( + "did not converge in {0:d} iterations".format(iteration) + ) break # printing pKa iterations # formerly was conditioned on if options.verbosity >= 2 - now unnecessary str_ = ' ' for index in range(iteration+1): str_ += "{0:>8d}".format(index) - debug(str_) + _LOGGER.debug(str_) for itres in iteratives: str_ = "{0:s} ".format(itres.label) for pka in itres.pka_iter: str_ += "{0:>8.2f}".format(pka) if not itres.converged: str_ += " *" - debug(str_) + _LOGGER.debug(str_) # creating real determinants and adding them to group object for itres in iteratives: for type_ in ['sidechain', 'backbone', 'coulomb']: for interaction in itres.determinants[type_]: - #info('done',itres.group.label,interaction[0],interaction[1]) value = interaction[1] if value > UNK_MIN_VALUE or value < -UNK_MIN_VALUE: group = interaction[0] diff --git a/propka/lib.py b/propka/lib.py index 2655935..0d1f258 100644 --- a/propka/lib.py +++ b/propka/lib.py @@ -11,10 +11,7 @@ import argparse import pkg_resources -_LOGGER = logging.getLogger("propka") -_STDOUT_HANDLER = logging.StreamHandler(sys.stdout) -_STDOUT_HANDLER.setFormatter(logging.Formatter("%(message)s")) -_LOGGER.addHandler(_STDOUT_HANDLER) +_LOGGER = logging.getLogger(__name__) EXPECTED_ATOM_NUMBERS = {'ALA': 5, 'ARG': 11, 'ASN': 8, 'ASP': 8, 'CYS': 6, @@ -53,7 +50,7 @@ def protein_precheck(conformations, names): "{res:s} in conformation {conf:s}".format( num=len(res_atoms), res=residue_label, conf=name)) - warning(str_) + _LOGGER.warning(str_) continue # check number of atoms in residue if len(res_atoms) != EXPECTED_ATOM_NUMBERS[res_name]: @@ -61,7 +58,7 @@ def protein_precheck(conformations, names): "{res:s} in conformation {conf:s}".format( num=len(res_atoms), res=residue_label, conf=name)) - warning(str_) + _LOGGER.warning(str_) def resid_from_atom(atom): @@ -101,7 +98,7 @@ def make_molecule(atom, atoms): list of atoms """ bonded_atoms = [a for a in atoms if atom in a.bonded_atoms] - res_atoms = [atom,] + res_atoms = [atom] for bond_atom in bonded_atoms: if bond_atom in atoms: atoms.remove(bond_atom) @@ -190,9 +187,9 @@ def build_parser(parser=None): """Build an argument parser for PROPKA. Args: - parser: existing parser. If this is not None, then the PROPKA parser will - be created as a subparser to this existing parser. Otherwise, a - new parser will be created. + parser: existing parser. If this is not None, then the PROPKA parser + will be created as a subparser to this existing parser. + Otherwise, a new parser will be created. Returns: ArgumentParser object. """ @@ -209,7 +206,10 @@ def build_parser(parser=None): group.add_argument("input_pdb", help="read data from ") group.add_argument( "-f", "--file", action="append", dest="filenames", default=[], - help="read data from , i.e. is added to arguments") + help=( + "read data from , i.e. is added to arguments" + ) + ) group.add_argument( "-r", "--reference", dest="reference", default="neutral", help=("setting which reference to use for stability calculations " @@ -221,8 +221,8 @@ def build_parser(parser=None): group.add_argument( "-i", "--titrate_only", dest="titrate_only", 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"')) + 'be a comma-separated list of "chain:resnum" values; for ' + 'example: -i "A:10,A:11"')) group.add_argument( "-t", "--thermophile", action="append", dest="thermophiles", help=("defining a thermophile filename; usually used in " @@ -265,7 +265,11 @@ def build_parser(parser=None): "related properties [0.0, 14.0, 0.1]")) group.add_argument( "--mutator", dest="mutator", - help="setting approach for mutating [alignment/scwrl/jackal]") + help=( + "setting approach for mutating " + "[alignment/scwrl/jackal]" + ) + ) group.add_argument( "--mutator-option", dest="mutator_options", action="append", help="setting property for mutator [e.g. type=\"side-chain\"]") @@ -340,14 +344,14 @@ def make_tidy_atom_label(name, element): Returns: string """ - if len(name) > 4: # if longer than 4, just truncate the name + if len(name) > 4: # if longer than 4, just truncate the name label = name[0:4] - elif len(name) == 4: # if length is 4, otherwise use the name as it is + elif len(name) == 4: # if length is 4, otherwise use the name as it is label = name - else: # if less than 4 characters long, insert white space as needed + else: # if less than 4 characters long, insert white space as needed if len(element) == 1: label = ' {0:<3s}'.format(name) - else: # The element should occupy the two first chars + else: # The element should occupy the two first chars label = '{0:<4s}'.format(name) return label @@ -368,47 +372,3 @@ def get_sorted_configurations(configuration_keys): def configuration_compare(conf): """TODO - figure out what this function does.""" return 100*int(conf[1:-2]) + ord(conf[-1]) - - -def _args_to_str(arg_list): - """Summarize list of arguments in string. - - Args: - arg_list: list of arguments - Returns: - string - """ - return " ".join(map(str, arg_list)) - - -def info(*args): - """Log a message to info. - - Level defaults to INFO unless overridden. - - Args: - args: argument list - """ - _LOGGER.info(_args_to_str(args)) - - -def debug(*args): - """Log a message to debug. - - Level defaults to DEBUG unless overridden. - - Args: - args: argument list - """ - _LOGGER.debug(_args_to_str(args)) - - -def warning(*args): - """Log a message to warning. - - Level defaults to WARNING unless overridden. - - Args: - args: argument list - """ - _LOGGER.warning(_args_to_str(args)) diff --git a/propka/ligand_pka_values.py b/propka/ligand_pka_values.py index bc73dda..d64399f 100644 --- a/propka/ligand_pka_values.py +++ b/propka/ligand_pka_values.py @@ -9,11 +9,15 @@ programs are required). .. _Marvin: https://chemaxon.com/products/marvin """ +import logging import os import subprocess import sys from propka.output import write_mol2_for_atoms -from propka.lib import info, warning, split_atoms_into_molecules +from propka.lib import split_atoms_into_molecules + + +_LOGGER = logging.getLogger(__name__) class LigandPkaValues: @@ -29,9 +33,9 @@ class LigandPkaValues: # attempt to find Marvin executables in the path self.molconvert = self.find_in_path('molconvert') self.cxcalc = self.find_in_path('cxcalc') - info('Found Marvin executables:') - info(self.cxcalc) - info(self.molconvert) + _LOGGER.info('Found Marvin executables:') + _LOGGER.info(self.cxcalc) + _LOGGER.info(self.molconvert) @staticmethod def find_in_path(program): @@ -50,7 +54,7 @@ class LigandPkaValues: if len(locs) == 0: str_ = "'Error: Could not find {0:s}.".format(program) str_ += ' Please make sure that it is found in the path.' - info(str_) + _LOGGER.info(str_) sys.exit(-1) return locs[0] @@ -146,7 +150,7 @@ class LigandPkaValues: "Didn't find a user-modified file '{0:s}' " "- generating one".format( filename)) - warning(errstr) + _LOGGER.warning(errstr) write_mol2_for_atoms(atoms, filename) # Marvin calculate pKa values fmt = ( @@ -159,17 +163,22 @@ class LigandPkaValues: [self.cxcalc, filename]+options.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() if len(errors) > 0: - info('***********************************************************' - '*********************************************') - info('* Warning: Marvin execution failed: ' - ' *') - info('* {0:<100s} *'.format(errors)) - info('* ' - ' *') - info('* Please edit the ligand mol2 file and re-run PropKa with ' - 'the -l option: {0:>29s} *'.format(filename)) - info('***********************************************************' - '*********************************************') + _LOGGER.info( + '***********************************************************' + '*********************************************') + _LOGGER.info( + '* Warning: Marvin execution failed: ' + ' *') + _LOGGER.info('* {0:<100s} *'.format(errors)) + _LOGGER.info( + '* ' + ' *') + _LOGGER.info( + '* Please edit the ligand mol2 file and re-run PropKa with ' + 'the -l option: {0:>29s} *'.format(filename)) + _LOGGER.info( + '***********************************************************' + '*********************************************') sys.exit(-1) # extract calculated pkas indices, pkas, types = self.extract_pkas(output) @@ -177,7 +186,9 @@ class LigandPkaValues: for i, index in enumerate(indices): atoms[index].marvin_pka = pkas[i] atoms[index].charge = {'a': -1, 'b': 1}[types[i]] - info('{0:s} model pKa: {1:<.2f}'.format(atoms[index], pkas[i])) + _LOGGER.info( + '{0:s} model pKa: {1:<.2f}'.format(atoms[index], pkas[i]) + ) @staticmethod def extract_pkas(output): diff --git a/propka/molecular_container.py b/propka/molecular_container.py index 45473b2..dbd0c0a 100644 --- a/propka/molecular_container.py +++ b/propka/molecular_container.py @@ -4,11 +4,15 @@ PDB molecular container Molecular container for storing all contents of PDB files. """ +import logging import os import propka.version from propka.output import write_propka, write_pka, print_header, print_result from propka.conformation_container import ConformationContainer -from propka.lib import info, warning, make_grid +from propka.lib import make_grid + + +_LOGGER = logging.getLogger(__name__) # TODO - these are constants whose origins are a little murky @@ -55,13 +59,11 @@ class MolecularContainer: def find_covalently_coupled_groups(self): """Find covalently coupled groups.""" - info('-' * 103) for name in self.conformation_names: self.conformations[name].find_covalently_coupled_groups() def find_non_covalently_coupled_groups(self): """Find non-covalently coupled groups.""" - info('-' * 103) verbose = self.options.display_coupled_residues for name in self.conformation_names: self.conformations[name].find_non_covalently_coupled_groups( @@ -110,7 +112,7 @@ class MolecularContainer: 'Group {0:s} could not be found in ' 'conformation {1:s}.'.format( group.atom.residue_label, name)) - warning(str_) + _LOGGER.warning(str_) # ... and store the average value avr_group = avr_group / len(self.conformation_names) avr_conformation.groups.append(avr_group) diff --git a/propka/output.py b/propka/output.py index f8784d3..cf9aaf7 100644 --- a/propka/output.py +++ b/propka/output.py @@ -4,11 +4,14 @@ Output Output routines. """ +import logging from datetime import date -from propka.lib import info from . import __version__ +_LOGGER = logging.getLogger(__name__) + + def open_file_for_writing(input_file): """Open file or file-like stream for writing. @@ -49,7 +52,7 @@ def print_header(): str_ = "{0:s}\n".format(get_propka_header()) str_ += "{0:s}\n".format(get_references_header()) str_ += "{0:s}\n".format(get_warning_header()) - info(str_) + _LOGGER.info("\n%s", str_) def write_pdb_for_protein( @@ -69,7 +72,7 @@ def write_pdb_for_protein( filename = "{0:s}.pdb".format(protein.name) # TODO - this would be better as a context manager pdbfile = open(filename, 'w') - info("writing pdbfile {0:s}".format(filename)) + _LOGGER.info("writing pdbfile {0:s}".format(filename)) close_file = True else: # don't close the file, it was opened in a different place @@ -122,7 +125,7 @@ def write_pka(protein, parameters, filename=None, conformation='1A', # TODO - this would be much better with a context manager file_ = open(filename, 'w') if verbose: - info("Writing {0:s}".format(filename)) + _LOGGER.info("Writing {0:s}".format(filename)) # writing propka header str_ = "{0:s}\n".format(get_propka_header()) str_ += "{0:s}\n".format(get_references_header()) @@ -172,7 +175,7 @@ def print_tm_profile(protein, reference="neutral", window=[0., 14., 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_) - info(str_) + _LOGGER.info(str_) def print_result(protein, conformation, parameters): @@ -196,9 +199,9 @@ def print_pka_section(protein, conformation, parameters): """ # geting the determinants section str_ = get_determinant_section(protein, conformation, parameters) - info(str_) + _LOGGER.info("pKa determinants:\n%s", str_) str_ = get_summary_section(protein, conformation, parameters) - info(str_) + _LOGGER.info("pKa summary:\n%s", str_) def get_determinant_section(protein, conformation, parameters): @@ -291,8 +294,9 @@ def get_folding_profile_section( else: str_ += "The pH of optimum stability is {0:>4.1f}".format(ph_opt) str_ += ( - " for which the free energy is {0:>6.1f} kcal/mol at 298K\n".format( - dg_opt)) + " for which the free energy is {0:>6.1f} kcal/mol at " + "298K\n".format(dg_opt) + ) if dg_min is None or dg_max is None: str_ += "Could not determine pH values where the free energy" str_ += " is within 80 % of minimum\n" @@ -332,7 +336,10 @@ def get_charge_profile_section(protein, conformation='AVR', _=None): if pi_pro is None or pi_mod is None: str_ += "Could not determine the pI\n\n" else: - str_ += f"The pI is {pi_pro:>5.2f} (folded) and {pi_mod:>5.2f} (unfolded)\n" + str_ += ( + f"The pI is {pi_pro:>5.2f} (folded) and {pi_mod:>5.2f} " + f"(unfolded)\n" + ) return str_ @@ -590,6 +597,7 @@ def write_mol2_for_atoms(atoms, filename): out.write(substructure_section) out.close() + def write_propka(molecular_container, filename): """Write PROPKA input file for molecular container. diff --git a/propka/parameters.py b/propka/parameters.py index 923c687..aa9abcc 100644 --- a/propka/parameters.py +++ b/propka/parameters.py @@ -2,13 +2,18 @@ Configuration file parameters ============================= -Holds parameters and settings that can be set in :file:`propka.cfg`. The file format consists of lines of ``keyword value [value ...]``, blank lines, and comment lines (introduced with ``#``). +Holds parameters and settings that can be set in :file:`propka.cfg`. The file +format consists of lines of ``keyword value [value ...]``, blank lines, and +comment lines (introduced with ``#``). The module attributes below list the names and types of all key words in configuration file. """ -from propka.lib import info, warning +import logging + + +_LOGGER = logging.getLogger(__name__) #: matrices @@ -126,7 +131,7 @@ class Parameters: """ dict_ = getattr(self, words[0]) key = words[1] - if not key in dict_: + if key not in dict_: dict_[key] = [] for value in words[2:]: if isinstance(value, list): @@ -204,12 +209,12 @@ class Parameters: def print_interaction_parameters(self): """Print interaction parameters.""" - info('--------------- Model pKa values ----------------------') + _LOGGER.info('--------------- Model pKa values ----------------------') for k in self.model_pkas: - info('{0:>3s} {1:8.2f}'.format(k, self.model_pkas[k])) + _LOGGER.info('{0:>3s} {1:8.2f}'.format(k, self.model_pkas[k])) - info('') - info('--------------- Interactions --------------------------') + _LOGGER.info('') + _LOGGER.info('--------------- Interactions --------------------------') agroups = [ 'COO', 'HIS', 'CYS', 'TYR', 'SER', 'N+', 'LYS', 'AMD', 'ARG', 'TRP', 'ROH', 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', @@ -234,7 +239,9 @@ class Parameters: map_interaction = '' if group2 in map_: for val in map_[group2]: - fmt = "|{grp1:>3s} {grp2:>3s} {mat:1s} {val1:4} {val2:4}" + fmt = ( + "|{grp1:>3s} {grp2:>3s} {mat:1s} {val1:4} {val2:4}" + ) map_interaction += fmt.format( group1, val, self.interaction_matrix[group1][val], self.sidechain_cutoffs.get_value(group1, val)[0], @@ -260,18 +267,18 @@ class Parameters: group1, group2)[1] != 4)): map_interaction += '? ' - info(interaction, map_interaction) + _LOGGER.info("%s %s", interaction, map_interaction) if group1 == group2: break - info('-') - info('--------------- Exceptions ----------------------------') - info('COO-HIS', self.COO_HIS_exception) - info('OCO-HIS', self.OCO_HIS_exception) - info('CYS-HIS', self.CYS_HIS_exception) - info('CYS-CYS', self.CYS_CYS_exception) + _LOGGER.info('-') + _LOGGER.info('--------------- Exceptions ----------------------------') + _LOGGER.info('COO-HIS %s', self.COO_HIS_exception) + _LOGGER.info('OCO-HIS %s', self.OCO_HIS_exception) + _LOGGER.info('CYS-HIS %s', self.CYS_HIS_exception) + _LOGGER.info('CYS-CYS %s', self.CYS_CYS_exception) - info('--------------- Mapping -------------------------------') - info(""" + _LOGGER.info('--------------- Mapping -------------------------------') + _LOGGER.info(""" Titratable: CG ARG C2N ARG @@ -318,14 +325,16 @@ O2 "\\midrule", "\\endfirsthead", "", - "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous page}}}\\\\", + "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous " + "page}}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endhead", "", "\\midrule", - "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next page}}}\\\\", + "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next " + "page}}}\\\\", "\\endfoot", "", "\\bottomrule", @@ -350,11 +359,12 @@ O2 if group1 == group2: break str_ += ' \\end{{longtable}}\n' - info(str_) + _LOGGER.info(str_) def print_interactions_latex(self): """Print interactions in LaTeX.""" - # TODO - are these the same lists as above? Convert to module constants. + # TODO - are these the same lists as above? Convert to module + # constants. agroups = ['COO', 'HIS', 'CYS', 'TYR', 'SER', 'N+', 'LYS', 'AMD', 'ARG', 'TRP', 'ROH', 'CG', 'C2N', 'N30', 'N31', 'N32', 'N33', 'NAR', 'OCO', 'NP1', 'OH', 'O3', 'CL', 'F', 'NAM', @@ -371,14 +381,16 @@ O2 "\\midrule", "\\endfirsthead", "", - "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous page}}}\\\\", + "\\multicolumn{{5}}{{l}}{\\emph{{continued from the previous " + "page}}}\\\\", "\\toprule", "Group1 & Group2 & Interaction & c1 &c2 \\\\", "\\midrule", "\\endhead", "", "\\midrule", - "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next page}}}\\\\", + "\\multicolumn{{5}}{{r}}{\\emph{{continued on the next " + "page}}}\\\\", "\\endfoot", "", "\\bottomrule", @@ -388,7 +400,10 @@ O2 str_ = "\n".join(lines) for group1 in agroups: for group2 in agroups: - fmt = '{g1:>3s} & {g2:>3s} & {mat:1s} & {val1:>4s} & {val2:>4s}\\\\ \n' + fmt = ( + '{g1:>3s} & {g2:>3s} & {mat:1s} & {val1:>4s} & ' + '{val2:>4s}\\\\ \n' + ) str_ += fmt.format( group1, group2, self.interaction_matrix[group1][group2], str(self.sidechain_cutoffs.get_value(group1, group2)[0]), @@ -396,7 +411,7 @@ O2 if group1 == group2: break str_ += ' \\end{{longtable}}\n' - info(str_) + _LOGGER.info(str_) class InteractionMatrix: @@ -421,7 +436,7 @@ class InteractionMatrix: """ new_group = words[0] self.ordered_keys.append(new_group) - if not new_group in self.dictionary.keys(): + if new_group not in self.dictionary.keys(): self.dictionary[new_group] = {} for i, group in enumerate(self.ordered_keys): if len(words) > i+1: @@ -524,8 +539,8 @@ class PairwiseMatrix: str_ = ( 'Parameter value for {0:s}, {1:s} defined more ' 'than once'.format(key1, key2)) - warning(str_) - if not key1 in self.dictionary: + _LOGGER.warning(str_) + if key1 not in self.dictionary: self.dictionary[key1] = {} self.dictionary[key1][key2] = value diff --git a/propka/protonate.py b/propka/protonate.py index 69f1eb7..fe96f3a 100644 --- a/propka/protonate.py +++ b/propka/protonate.py @@ -7,11 +7,14 @@ The :class:`Protonate` processes a protons. """ +import logging import math import propka.bonds import propka.atom from propka.vector_algebra import rotate_vector_around_an_axis, Vector -from propka.lib import warning, debug + + +_LOGGER = logging.getLogger(__name__) class Protonate: @@ -49,7 +52,7 @@ class Protonate: Args: molecules: molecular containers """ - debug('----- Protonation started -----') + _LOGGER.debug('----- Protonation started -----') # Remove all currently present hydrogen atoms self.remove_all_hydrogen_atoms(molecules) # protonate all atoms @@ -81,11 +84,11 @@ class Protonate: if atom.type == 'atom': key = '{0:3s}-{1:s}'.format(atom.res_name, atom.name) if atom.terminal: - debug(atom.terminal) + _LOGGER.debug("%s", atom.terminal) key = atom.terminal if key in self.standard_charges: atom.charge = self.standard_charges[key] - debug('Charge', atom, atom.charge) + _LOGGER.debug('Charge %s %s', atom, atom.charge) atom.charge_set = True # atom is a ligand atom elif atom.type == 'hetatm': @@ -130,21 +133,25 @@ class Protonate: Args: atom: atom for calculation """ - debug('*'*10) - debug('Setting number of protons to add for', atom) + _LOGGER.debug('*'*10) + _LOGGER.debug('Setting number of protons to add for %s', atom) atom.number_of_protons_to_add = 8 - debug(" 8") + _LOGGER.debug(" 8") atom.number_of_protons_to_add -= self.valence_electrons[atom.element] - debug('Valence electrons: {0:>4d}'.format( + _LOGGER.debug('Valence electrons: {0:>4d}'.format( -self.valence_electrons[atom.element])) atom.number_of_protons_to_add -= len(atom.bonded_atoms) - debug('Number of bonds: {0:>4d}'.format(-len(atom.bonded_atoms))) + _LOGGER.debug( + 'Number of bonds: {0:>4d}'.format(-len(atom.bonded_atoms)) + ) atom.number_of_protons_to_add -= atom.num_pi_elec_2_3_bonds - debug('Pi electrons: {0:>4d}'.format(-atom.num_pi_elec_2_3_bonds)) + _LOGGER.debug( + 'Pi electrons: {0:>4d}'.format(-atom.num_pi_elec_2_3_bonds) + ) atom.number_of_protons_to_add += int(atom.charge) - debug('Charge: {0:>4.1f}'.format(atom.charge)) - debug('-'*10) - debug(atom.number_of_protons_to_add) + _LOGGER.debug('Charge: {0:>4.1f}'.format(atom.charge)) + _LOGGER.debug('-'*10) + _LOGGER.debug(atom.number_of_protons_to_add) def set_steric_number_and_lone_pairs(self, atom): """Set steric number and lone pairs for atom. @@ -155,39 +162,41 @@ class Protonate: # If we already did this, there is no reason to do it again if atom.steric_num_lone_pairs_set: return - debug('='*10) - debug('Setting steric number and lone pairs for', atom) + _LOGGER.debug('='*10) + _LOGGER.debug('Setting steric number and lone pairs for %s', atom) atom.steric_number = 0 - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Valence electrons', self.valence_electrons[atom.element])) atom.steric_number += self.valence_electrons[atom.element] - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of bonds', len(atom.bonded_atoms))) atom.steric_number += len(atom.bonded_atoms) - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of hydrogen atoms to add', atom.number_of_protons_to_add)) atom.steric_number += atom.number_of_protons_to_add - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of pi-electrons in double and triple bonds(-)', atom.num_pi_elec_2_3_bonds)) atom.steric_number -= atom.num_pi_elec_2_3_bonds - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of pi-electrons in conjugated double and triple bonds(-)', atom.num_pi_elec_conj_2_3_bonds)) atom.steric_number -= atom.num_pi_elec_conj_2_3_bonds - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of donated co-ordinated bonds', 0)) atom.steric_number += 0 - debug('{0:>65s}: {1:>4.1f}'.format( + _LOGGER.debug('{0:>65s}: {1:>4.1f}'.format( 'Charge(-)', atom.charge)) atom.steric_number -= atom.charge atom.steric_number = math.floor(atom.steric_number/2.0) atom.number_of_lone_pairs = ( - atom.steric_number-len(atom.bonded_atoms)-atom.number_of_protons_to_add) - debug('-'*70) - debug('{0:>65s}: {1:>4d}'.format( + atom.steric_number - len(atom.bonded_atoms) + - atom.number_of_protons_to_add + ) + _LOGGER.debug('-'*70) + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Steric number', atom.steric_number)) - debug('{0:>65s}: {1:>4d}'.format( + _LOGGER.debug('{0:>65s}: {1:>4d}'.format( 'Number of lone pairs', atom.number_of_lone_pairs)) atom.steric_num_lone_pairs_set = True @@ -198,12 +207,14 @@ class Protonate: atom: atom for calculation """ # decide which method to use - debug('PROTONATING', atom) + _LOGGER.debug('PROTONATING %s', atom) if atom.steric_number in list(self.protonation_methods.keys()): self.protonation_methods[atom.steric_number](atom) else: - warning('Do not have a method for protonating', atom, - '(steric number: {0:d})'.format(atom.steric_number)) + _LOGGER.warning( + 'Do not have a method for protonating %s %s', atom, + '(steric number: {0:d})'.format(atom.steric_number) + ) def trigonal(self, atom): """Add hydrogens in trigonal geometry. @@ -211,7 +222,9 @@ class Protonate: Args: atom: atom to protonate """ - debug('TRIGONAL - {0:d} bonded atoms'.format(len(atom.bonded_atoms))) + _LOGGER.debug( + 'TRIGONAL - {0:d} bonded atoms'.format(len(atom.bonded_atoms)) + ) rot_angle = math.radians(120.0) cvec = Vector(atom1=atom) # 0 bonds @@ -269,7 +282,7 @@ class Protonate: Args: atom: atom to protonate. """ - debug( + _LOGGER.debug( 'TETRAHEDRAL - {0:d} bonded atoms'.format(len(atom.bonded_atoms))) # TODO - might be good to move tetrahedral angle to constant rot_angle = math.radians(109.5) @@ -320,8 +333,9 @@ class Protonate: res_name=atom.res_name, chain_id=atom.chain_id, res_num=atom.res_num, - x=round(position.x, 3), # round of to three decimal points to - # avoid round-off differences in input file + x=round(position.x, 3), # round of to three decimal points to + # avoid round-off differences in input + # file y=round(position.y, 3), z=round(position.z, 3), occ=None, @@ -350,7 +364,7 @@ class Protonate: proton.residue_label = "{0:<3s}{1:>4d}{2:>2s}".format( proton.name, proton.res_num, proton.chain_id) i += 1 - debug('added', new_h, 'to', atom) + _LOGGER.debug('added %s %s %s', new_h, 'to', atom) def set_bond_distance(self, bvec, element): """Set bond distance between atom and element. @@ -368,6 +382,6 @@ class Protonate: str_ = ( 'Bond length for {0:s} not found, using the standard value ' 'of {1:f}'.format(element, dist)) - warning(str_) + _LOGGER.warning(str_) bvec = bvec.rescale(dist) return bvec diff --git a/propka/run.py b/propka/run.py index eed95f2..b646c59 100644 --- a/propka/run.py +++ b/propka/run.py @@ -11,18 +11,23 @@ function. If similar functionality is desired from a Python script """ import logging +import sys 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 -_LOGGER = logging.getLogger("PROPKA") +_LOGGER = logging.getLogger(__name__) def main(optargs=None): """Read in structure files, calculate pKa values, and print pKa files.""" # loading options, flags and arguments + logger = logging.getLogger("") + stdout_handler = logging.StreamHandler(sys.stdout) + stdout_handler.setFormatter(logging.Formatter("%(message)s")) + logger.addHandler(stdout_handler) optargs = optargs if optargs is not None else [] options = loadOptions(*optargs) pdbfiles = options.filenames @@ -56,7 +61,7 @@ def single(filename: str, optargs: tuple = (), stream=None, Given an input file "protein.pdb", run the equivalent of ``propka3 --mutation=N25R/N181D -v --pH=7.2 protein.pdb`` as:: - propka.run.single("protein.pdb", + propka.run.single("protein.pdb", optargs=["--mutation=N25R/N181D", "-v", "--pH=7.2"]) By default, a pKa file will be written. However in some cases one may diff --git a/propka/vector_algebra.py b/propka/vector_algebra.py index b91bd35..0ae9601 100644 --- a/propka/vector_algebra.py +++ b/propka/vector_algebra.py @@ -4,8 +4,12 @@ Vector calculations Vector algebra for PROPKA. """ +import logging import math -from propka.lib import info, get_sorted_configurations +from propka.lib import get_sorted_configurations + + +_LOGGER = logging.getLogger(__name__) class Vector: @@ -63,7 +67,7 @@ class Vector: elif type(other) in [int, float]: return Vector(self.x * other, self.y * other, self.z * other) else: - info('{0:s} not supported'.format(type(other))) + _LOGGER.info('{0:s} not supported'.format(type(other))) raise TypeError def __rmul__(self, other): diff --git a/propka/version.py b/propka/version.py index 93f2c65..9d1edf5 100644 --- a/propka/version.py +++ b/propka/version.py @@ -6,7 +6,7 @@ Contains version-specific methods and parameters. TODO - this module unnecessarily confuses the code. Can we eliminate it? """ -from propka.lib import info +import logging from propka.hydrogens import setup_bonding_and_protonation, setup_bonding from propka.hydrogens import setup_bonding_and_protonation_30_style from propka.energy import radial_volume_desolvation, calculate_pair_weight @@ -16,6 +16,9 @@ from propka.energy import coulomb_energy, check_exceptions from propka.energy import backbone_reorganization +_LOGGER = logging.getLogger(__name__) + + class Version: """Store version-specific methods and parameters.""" def __init__(self, parameters): @@ -140,12 +143,18 @@ class VersionA(Version): [v, [c1, c3]] TODO - figure out what this is """ if backbone_atom.group_type == 'BBC': - if atom.group_type in self.parameters.backbone_CO_hydrogen_bond.keys(): + if ( + atom.group_type in + self.parameters.backbone_CO_hydrogen_bond.keys() + ): [v, c1, c2] = self.parameters.backbone_CO_hydrogen_bond[ atom.group_type] return [v, [c1, c2]] if backbone_atom.group_type == 'BBN': - if atom.group_type in self.parameters.backbone_NH_hydrogen_bond.keys(): + if ( + atom.group_type in + self.parameters.backbone_NH_hydrogen_bond.keys() + ): [v, c1, c2] = self.parameters.backbone_NH_hydrogen_bond[ atom.group_type] return [v, [c1, c2]] @@ -159,7 +168,7 @@ class SimpleHB(VersionA): """Initialize object with parameters.""" # set the calculation rutines used in this version super().__init__(parameters) - info('Using simple hb model') + _LOGGER.info('Using simple hb model') def get_hydrogen_bond_parameters(self, atom1, atom2): """Get hydrogen bond parameters for two atoms. @@ -193,7 +202,7 @@ class ElementBasedLigandInteractions(VersionA): """Initialize object with parameters.""" # set the calculation rutines used in this version super().__init__(parameters) - info('Using detailed SC model!') + _LOGGER.info('Using detailed SC model!') return def get_hydrogen_bond_parameters(self, atom1, atom2): @@ -259,8 +268,9 @@ class ElementBasedLigandInteractions(VersionA): res = self.parameters.hydrogen_bonds.get_value( elements[0], elements[1]) if not res: - info( - 'Could not determine backbone interaction parameters for:', + _LOGGER.info( + 'Could not determine backbone interaction parameters ' + 'for: %s %s', backbone_atom, atom) return None return None