[med-svn] [Git][med-team/plip][master] 6 commits: New upstream version 1.4.0~b+dfsg

Alexandre Mestiashvili gitlab at salsa.debian.org
Thu Apr 12 14:57:15 BST 2018


Alexandre Mestiashvili pushed to branch master at Debian Med / plip


Commits:
997353ae by Alexandre Mestiashvili at 2018-04-12T12:05:48+02:00
New upstream version 1.4.0~b+dfsg
- - - - -
f89991ca by Alexandre Mestiashvili at 2018-04-12T12:05:48+02:00
Update upstream source from tag 'upstream/1.4.0_b+dfsg'

Update to upstream version '1.4.0~b+dfsg'
with Debian dir 44455e4a5f9b348df0ea8102b8e4116cca7a94be
- - - - -
e5dcf2eb by Alexandre Mestiashvili at 2018-04-12T12:41:07+02:00
Update d/control, add python-future build-dep, update maintainer email, fix VCS

Bump policy and set debhelper to 11

- - - - -
76c6a3a2 by Alexandre Mestiashvili at 2018-04-12T12:41:49+02:00
Set compat to 11

- - - - -
b1582e00 by Alexandre Mestiashvili at 2018-04-12T12:50:15+02:00
Remove unused lintian override

- - - - -
caf52b10 by Alexandre Mestiashvili at 2018-04-12T12:56:54+02:00
Update changelog

- - - - -


20 changed files:

- CHANGES.txt
- DOCUMENTATION.md
- − TODO.txt
- debian/changelog
- debian/compat
- debian/control
- − debian/plip.lintian-overrides
- plip/modules/config.py
- plip/modules/detection.py
- plip/modules/mp.py
- plip/modules/plipxml.py
- plip/modules/preparation.py
- plip/modules/pymolplip.py
- plip/modules/report.py
- plip/modules/supplemental.py
- plip/modules/visualize.py
- plip/modules/webservices.py
- plip/plipcmd
- plip/test/test_basic_functions.py
- setup.py


Changes:

=====================================
CHANGES.txt
=====================================
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,8 +1,11 @@
 Changelog
 ---------
 
-### Next version
--
+# 1.4.0
+* __Full Python 3 Compatibility__
+* __Read PDB files from stdin with "-f -" and write to stdout with "-O" (capital "O")__
+* Improves handling of fixed PDB files
+* Option to turn off writing fixed PDB structures to a file ("--nofixfile")
 
 ### 1.3.5
 * Preparation for Python 3: Imports


=====================================
DOCUMENTATION.md
=====================================
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -87,7 +87,7 @@ plip -i 1vsn -v
 The command above will fetch the PDB entry 1vsn from the server, analyze all interactions and print out the results (verbose mode).
 No output files are produced at this point.
 
-The same can be done for local PDB files.
+The same can be done for local PDB files (-f <file>) or for reading from stdin (-f -).
 
 ```bash
 wget http://files.rcsb.org/download/1EVE.pdb
@@ -99,6 +99,7 @@ The output formats can be added in any combination, currently including:
 * Text report files (`-t`, human-readable)
 * PyMOL session files (`-y`)
 * Ray-traced images (`-p`)
+* writing to stdout (`-O`), to be used in combination with XML or text report files
 
 ```bash
 plip -i 1osn -pyx
@@ -278,7 +279,7 @@ The distance between the other ring center and the projected point (i.e. the off
 This value corresponds approximately to the radius of benzene + 0.6 Å.
 
 ##### π-Cation Interactions
-π-Cation interactions are reported for each pairing of a positive charge and an aromatic ring if the distance between the charge center and the aromatic ring center is less than PICATION_DIST_MAX.
+π-Cation interactions are reported for each pairing of a positive charge and an aromatic ring if the distance between the charge center and the aromatic ring center is less than PICATION_DIST_MAX and the offset between the ring center and the charge is no larger than PISTACK_OFFSET_MAX.
 In the case of a putative π-cation interaction with a tertiary amine of the ligand, an additional angle criterion is applied (see documentation in the source code).
 
 ##### Salt Bridges


=====================================
TODO.txt deleted
=====================================
--- a/TODO.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Possible future features
-========================
-
-* Python 3 support
-* support special characters in filenames (e.g. spanish accents), currently cause problems in XML report
-* support for mmcif format
-* support presets for hydrogenation
-* detection of steric clashes
-* detection of anion-pi interactions
-* detection of electrostatic repulsion force_string
-* detection of Keesom forces
-* weak hydrogen bonding
-* visualization: show hydrogen atoms in PyMOL for hydrogen bonds and adapt interaction vector accordingly
-* use SMARTS for detection of chemical features (charged groups, etc.)


=====================================
debian/changelog
=====================================
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+plip (1.4.0~b+dfsg-1) unstable; urgency=medium
+
+  [ Steffen Möller ]
+  * Updated RRID in d/u/metadata
+
+  [ Andreas Tille ]
+  * Remove invalid fields from debian/upstream/metadata
+
+  [ Alexandre Mestiashvili ]
+  * New upstream version 1.4.0~b+dfsg
+  * Update d/control:
+    - Add python-future build-dep
+    - Update uploader's email
+    - fix VCS-* fields to point to salsa
+    - Set debhelper and compat to 11
+  * Remove unused lintian override
+
+ -- Alexandre Mestiashvili <mestia at debian.org>  Thu, 12 Apr 2018 12:51:07 +0200
+
 plip (1.3.5+dfsg-1) unstable; urgency=medium
 
   * Bump Standards-Version to 4.1.1


=====================================
debian/compat
=====================================
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+11


=====================================
debian/control
=====================================
--- a/debian/control
+++ b/debian/control
@@ -1,9 +1,9 @@
 Source: plip
 Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Alexandre Mestiashvili <alex at biotec.tu-dresden.de>
+Uploaders: Alexandre Mestiashvili <mestia at debian.org>
 Section: python
 Priority: optional
-Build-Depends: debhelper (>= 9),
+Build-Depends: debhelper (>= 11),
                dh-python,
                help2man,
                pymol,
@@ -11,10 +11,11 @@ Build-Depends: debhelper (>= 9),
                python-lxml,
                python-numpy,
                python-openbabel,
-               python-setuptools
-Standards-Version: 4.1.1
-Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/plip.git
-Vcs-Git: https://anonscm.debian.org/git/debian-med/plip.git
+               python-setuptools,
+               python-future
+Standards-Version: 4.1.3
+Vcs-Browser: https://salsa.debian.org/med-team/plip
+Vcs-Git: https://salsa.debian.org/med-team/plip.git
 Homepage: https://projects.biotec.tu-dresden.de/plip-web/plip/
 
 Package: plip


=====================================
debian/plip.lintian-overrides deleted
=====================================
--- a/debian/plip.lintian-overrides
+++ /dev/null
@@ -1 +0,0 @@
-plip: spelling-error-in-manpage


=====================================
plip/modules/config.py
=====================================
--- a/plip/modules/config.py
+++ b/plip/modules/config.py
@@ -10,12 +10,15 @@ XML = False
 TXT = False
 PICS = False
 PYMOL = False
+STDOUT = False
+RAWSTRING = False # use raw strings for input / output
 OUTPATH = './'
 BASEPATH = './'
 BREAKCOMPOSITE = False  # Break up composite ligands with covalent bonds
 ALTLOC = False  # Consider alternate locations
 PLUGIN_MODE = False  # Special mode for PLIP in Plugins (e.g. PyMOL)
 NOFIX = False  # Turn off fixing of errors in PDB files
+NOFIXFILE = False # Turn off writing to files for fixed PDB structures
 PEPTIDES = []  # Definition which chains should be considered as peptide ligands
 INTRA = None
 KEEPMOD = False


=====================================
plip/modules/detection.py
=====================================
--- a/plip/modules/detection.py
+++ b/plip/modules/detection.py
@@ -9,8 +9,8 @@ import itertools
 from collections import defaultdict
 
 # Own modules
-from plip.modules.supplemental import *
-import plip.modules.config
+from .supplemental import *
+from . import config
 
 
 def filter_contacts(pairings):


=====================================
plip/modules/mp.py
=====================================
--- a/plip/modules/mp.py
+++ b/plip/modules/mp.py
@@ -5,6 +5,7 @@ mp.py - Functions for parallel processing
 
 # Python Standard Library
 from __future__ import division
+from builtins import zip
 import multiprocessing
 import itertools
 from numpy import asarray
@@ -28,7 +29,7 @@ def universal_worker(input_pair):
 
 def pool_args(function, sequence, kwargs):
     """Return a single iterator of n elements of lists of length 3, given a sequence of len n."""
-    return itertools.izip(itertools.repeat(function), sequence, itertools.repeat(kwargs))
+    return zip(itertools.repeat(function), sequence, itertools.repeat(kwargs))
 
 
 def parallel_fn(f):


=====================================
plip/modules/plipxml.py
=====================================
--- a/plip/modules/plipxml.py
+++ b/plip/modules/plipxml.py
@@ -9,7 +9,11 @@ from lxml import etree
 import itertools
 from itertools import groupby
 import sys
-import urllib2
+
+try: # Python 3
+    from urllib.request import urlopen
+except ImportError: # Fallback Python 2.x
+    from urllib2 import urlopen
 
 
 class XMLStorage:
@@ -190,6 +194,7 @@ class BSite(XMLStorage):
         self.longname = self.getdata(bindingsite, 'identifiers/longname')
         self.ligtype = self.getdata(bindingsite, 'identifiers/ligtype')
         self.smiles = self.getdata(bindingsite, 'identifiers/smiles')
+        self.inchikey = self.getdata(bindingsite, 'identifiers/inchikey')
 
         # Information on binding site members
         self.members = []
@@ -298,7 +303,7 @@ class PLIPXMLREST(PLIPXML):
     def load_data(self, pdbid):
         """Loads and parses an XML resource and saves it as a tree if successful"""
         #TODO Implement error handling
-        f = urllib2.urlopen("http://projects.biotec.tu-dresden.de/plip-rest/pdb/%s?format=xml" % pdbid.lower())
+        f = urlopen("http://projects.biotec.tu-dresden.de/plip-rest/pdb/%s?format=xml" % pdbid.lower())
         try:
             self.doc = etree.parse(f)
         except IOError:


=====================================
plip/modules/preparation.py
=====================================
--- a/plip/modules/preparation.py
+++ b/plip/modules/preparation.py
@@ -6,12 +6,13 @@ preparation.py - Prepare PDB input files for processing.
 
 # Python Standard Library
 from __future__ import absolute_import
+from builtins import filter
 from operator import itemgetter
 
 # Own modules
-from plip.modules.detection import *
-from plip.modules.supplemental import *
-import plip.modules.config
+from .detection import *
+from .supplemental import *
+from . import config
 
 
 ################
@@ -37,10 +38,11 @@ class PDBParser:
         IV. Alternative conformations
         """
         if self.as_string:
-            fil = self.pdbpath.split('\n')
+            fil = self.pdbpath.rstrip('\n').split('\n') # Removing trailing newline character
         else:
-            fil = read(self.pdbpath).readlines()
-        # #@todo Also consider SSBOND entries here
+            f = read(self.pdbpath)
+            fil = f.readlines()
+            f.close()
         corrected_lines = []
         i, j = 0, 0  # idx and PDB numbering
         d = {}
@@ -75,7 +77,6 @@ class PDBParser:
             corrected_pdb = self.pdbpath
             corrected_lines = fil
 
-
         for line in corrected_lines:
             if line.startswith(("ATOM", "HETATM")):
                 # Retrieve alternate conformations
@@ -293,7 +294,7 @@ class LigandFinder:
         hetatoms = set()
         for obresidue in kmer:
             hetatoms_res = set([(obatom.GetIdx(), obatom) for obatom in pybel.ob.OBResidueAtomIter(obresidue)
-                                if not obatom.IsHydrogen()])
+                                if obatom.GetAtomicNum() != 1])
 
             if not config.ALTLOC:
                 # Remove alternative conformations (standard -> True)
@@ -488,7 +489,7 @@ class Mol:
         """Find all possible hydrogen bond acceptors"""
         data = namedtuple('hbondacceptor', 'a a_orig_atom a_orig_idx type')
         a_set = []
-        for atom in itertools.ifilter(lambda at: at.OBAtom.IsHbondAcceptor(), all_atoms):
+        for atom in filter(lambda at: at.OBAtom.IsHbondAcceptor(), all_atoms):
             if atom.atomicnum not in [9, 17, 35, 53] and atom.idx not in self.altconf:  # Exclude halogen atoms
                 a_orig_idx = self.Mapper.mapid(atom.idx, mtype=self.mtype, bsid=self.bsid)
                 a_orig_atom = self.Mapper.id_to_atom(a_orig_idx)
@@ -978,6 +979,7 @@ class Ligand(Mol):
         self.complex = cclass
         self.molecule = ligand.mol  # Pybel Molecule
         self.smiles = self.molecule.write(format='can')  # SMILES String
+        self.inchikey = self.molecule.write(format='inchikey')
         self.can_to_pdb = ligand.can_to_pdb
         if not len(self.smiles) == 0:
             self.smiles = self.smiles.split()[0]
@@ -1256,7 +1258,7 @@ class PDBComplex:
         self.sourcefiles = {}
         self.information = {}
         self.corrected_pdb = ''
-        self.output_path = '/tmp'
+        self._output_path = '/tmp'
         self.pymol_name = None
         self.modres = set()
         self.resis = []
@@ -1284,7 +1286,7 @@ class PDBComplex:
         pdbparser = PDBParser(pdbpath, as_string=as_string)  # Parse PDB file to find errors and get additonal data
         # #@todo Refactor and rename here
         self.Mapper.proteinmap = pdbparser.proteinmap
-        self.Mapper.reversed_proteinmap = inv_map = {v: k for k, v in self.Mapper.proteinmap.iteritems()}
+        self.Mapper.reversed_proteinmap = inv_map = {v: k for k, v in self.Mapper.proteinmap.items()}
         self.modres = pdbparser.modres
         self.covalent = pdbparser.covalent
         self.altconf = pdbparser.altconformations
@@ -1294,20 +1296,23 @@ class PDBComplex:
             if pdbparser.num_fixed_lines > 0:
                 write_message('%i lines automatically fixed in PDB input file.\n' % pdbparser.num_fixed_lines)
                 # Save modified PDB file
-                basename = os.path.basename(pdbpath).split('.')[0]
+                if not as_string:
+                    basename = os.path.basename(pdbpath).split('.')[0]
+                else:
+                    basename = "from_stdin"
                 pdbpath_fixed = tmpfile(prefix='plipfixed.' + basename + '_', direc=self.output_path)
                 create_folder_if_not_exists(self.output_path)
                 self.sourcefiles['pdbcomplex'] = pdbpath_fixed
                 self.corrected_pdb = re.sub(r'[^\x00-\x7F]+', ' ', self.corrected_pdb)  # Strip non-unicode chars
-                with open(pdbpath_fixed, 'w') as f:
-                    f.write(self.corrected_pdb)
+                if not config.NOFIXFILE: # Only write to file if this option is not activated
+                    with open(pdbpath_fixed, 'w') as f:
+                        f.write(self.corrected_pdb)
                 self.information['pdbfixes'] = True
 
-        if as_string:
-            self.protcomplex, self.filetype = read_pdb(self.sourcefiles['pdbstring'], as_string=as_string)
-        else:
+
+        if not as_string:
             self.sourcefiles['filename'] = os.path.basename(self.sourcefiles['pdbcomplex'])
-            self.protcomplex, self.filetype = read_pdb(self.sourcefiles['pdbcomplex'], as_string=as_string)
+        self.protcomplex, self.filetype = read_pdb(self.corrected_pdb, as_string=True)
 
         # Update the model in the Mapper class instance
         self.Mapper.original_structure = self.protcomplex.OBMol
@@ -1434,8 +1439,8 @@ class PDBComplex:
 
     @property
     def output_path(self):
-        return self.output_path
+        return self._output_path
 
     @output_path.setter
     def output_path(self, path):
-        self.output_path = tilde_expansion(path)
+        self._output_path = tilde_expansion(path)


=====================================
plip/modules/pymolplip.py
=====================================
--- a/plip/modules/pymolplip.py
+++ b/plip/modules/pymolplip.py
@@ -69,7 +69,7 @@ class PyMOLVisualizer:
         idlist = list(set(idlist))  # Remove duplicates
         if not selection_exists:
             cmd.select(selname, 'None')  # Empty selection first
-        idchunks = [idlist[i:i+chunksize] for i in xrange(0, len(idlist), chunksize)]
+        idchunks = [idlist[i:i+chunksize] for i in range(0, len(idlist), chunksize)]
         for idchunk in idchunks:
             cmd.select(selname, '%s or (id %s)' % (selname, '+'.join(map(str, idchunk))))
         if restrict is not None:


=====================================
plip/modules/report.py
=====================================
--- a/plip/modules/report.py
+++ b/plip/modules/report.py
@@ -3,18 +3,23 @@ Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand inter
 report.py - Write PLIP results to output files.
 """
 
+# Compatibility
+from __future__ import print_function
+from __future__ import absolute_import
 
 # Python Standard Library
 import time
 from operator import itemgetter
 import sys
-import config
+
+# Own modules
+from . import config
 
 
 # External libraries
 import lxml.etree as et
 
-__version__ = '1.3.4'
+__version__ = '1.4.0'
 
 class StructureReport:
     """Creates reports (xml or txt) for one structure/"""
@@ -50,7 +55,7 @@ class StructureReport:
         pdbfixes = et.SubElement(report, 'pdbfixes')
         pdbfixes.text = str(self.mol.information['pdbfixes'])
         filename = et.SubElement(report, 'filename')
-        filename.text = str(self.mol.sourcefiles['filename'])
+        filename.text = str(self.mol.sourcefiles.get('filename') or None)
         exligs = et.SubElement(report, 'excluded_ligands')
         for i, exlig in enumerate(self.excluded):
             e = et.SubElement(exligs, 'excluded_ligand', id=str(i + 1))
@@ -92,7 +97,10 @@ class StructureReport:
         if not as_string:
             et.ElementTree(self.xmlreport).write('%s/report.xml' % self.outpath, pretty_print=True, xml_declaration=True)
         else:
-            print et.tostring(self.xmlreport, pretty_print=True)
+            output = et.tostring(self.xmlreport, pretty_print=True)
+            if config.RAWSTRING:
+                output = repr(output)
+            print(output)
 
     def write_txt(self, as_string=False):
         """Write the TXT report"""
@@ -100,7 +108,10 @@ class StructureReport:
             with open('%s/report.txt' % self.outpath, 'w') as f:
                 [f.write(textline + '\n') for textline in self.txtreport]
         else:
-            print '\n'.join(self.txtreport)
+            output = '\n'.join(self.txtreport)
+            if config.RAWSTRING:
+                output = repr(output)
+            print(output)
 
 
 class BindingSiteReport:
@@ -350,6 +361,7 @@ class BindingSiteReport:
         composite = et.SubElement(identifiers, 'composite')
         members = et.SubElement(identifiers, 'members')
         smiles = et.SubElement(identifiers, 'smiles')
+        inchikey = et.SubElement(identifiers, 'inchikey')
 
         # Ligand properties. Number of (unpaired) functional atoms and rings.
         lig_properties = et.SubElement(report, 'lig_properties')
@@ -391,6 +403,7 @@ class BindingSiteReport:
         longname.text = self.longname
         ligtype.text = self.ligtype
         smiles.text = self.ligand.smiles
+        inchikey.text = self.ligand.inchikey
         num_heavy_atoms.text = str(self.ligand.heavy_atoms)  # Number of heavy atoms in ligand
         for i, member in enumerate(self.lig_members):
             bsid = ":".join(str(element) for element in member)


=====================================
plip/modules/supplemental.py
=====================================
--- a/plip/modules/supplemental.py
+++ b/plip/modules/supplemental.py
@@ -8,7 +8,7 @@ from __future__ import print_function
 from __future__ import absolute_import
 
 # PLIP Modules
-import plip.modules.config as config
+from . import config
 
 # Python standard library
 import re
@@ -92,7 +92,7 @@ def vector(p1, p2):
     :param p2: coordinates of point p2
     :returns : numpy array with vector coordinates
     """
-    return None if len(p1) != len(p2) else np.array([p2[i] - p1[i] for i in xrange(len(p1))])
+    return None if len(p1) != len(p2) else np.array([p2[i] - p1[i] for i in range(len(p1))])
 
 
 def vecangle(v1, v2, deg=True):
@@ -123,7 +123,7 @@ def centroid(coo):
     :param coo: Array of coordinate arrays
     :returns : centroid coordinates as list
     """
-    return map(np.mean, (([c[0] for c in coo]), ([c[1] for c in coo]), ([c[2] for c in coo])))
+    return list(map(np.mean, (([c[0] for c in coo]), ([c[1] for c in coo]), ([c[2] for c in coo]))))
 
 
 def projection(pnormal1, ppoint, tpoint):
@@ -334,15 +334,16 @@ def get_isomorphisms(reference, lig):
     return isomorphs
 
 
-def canonicalize(lig):
+def canonicalize(lig, preserve_bond_order=False):
     """Get the canonical atom order for the ligand."""
     atomorder = None
     # Get canonical atom order
 
     lig = pybel.ob.OBMol(lig.OBMol)
-    for bond in pybel.ob.OBMolBondIter(lig):
-        if bond.GetBondOrder() != 1:
-            bond.SetBondOrder(1)
+    if not preserve_bond_order:
+        for bond in pybel.ob.OBMolBondIter(lig):
+            if bond.GetBondOrder() != 1:
+                bond.SetBondOrder(1)
     lig.DeleteData(pybel.ob.StereoData)
     lig = pybel.Molecule(lig)
     testcan = lig.write(format='can')
@@ -398,33 +399,40 @@ def read(fil):
         zf = zipfile.ZipFile(fil, 'r')
         return zf.open(zf.infolist()[0].filename)
     else:
-        try:
-            codecs.open(fil, 'r', 'utf-8').read()
-            return codecs.open(fil, 'r', 'utf-8')
-        except UnicodeDecodeError:
-            return open(fil, 'r')
+        return open(fil, 'r')
+        #try:
+        #    codecs.open(fil, 'r', 'utf-8').read()
+        #    return codecs.open(fil, 'r', 'utf-8')
+        #except UnicodeDecodeError:
+        #    return open(fil, 'r')
 
 
 def readmol(path, as_string=False):
     """Reads the given molecule file and returns the corresponding Pybel molecule as well as the input file type.
     In contrast to the standard Pybel implementation, the file is closed properly."""
     supported_formats = ['pdb', 'mmcif']
-    obc = pybel.ob.OBConversion()
+    # Fix for Windows-generated files: Remove carriage return characters
+    if "\r" in path and as_string:
+        path = path.replace('\r', '')
 
     for sformat in supported_formats:
+        obc = pybel.ob.OBConversion()
         obc.SetInFormat(sformat)
         write_message("Detected {} as format. Now trying to read file with OpenBabel...\n".format(sformat), mtype='debug')
         mol = pybel.ob.OBMol()
 
         # Read molecules with single bond information
         if as_string:
-            read_file = pybel.readstring(format=sformat, filename=path, opt={"s": None})
+            try:
+                mymol = pybel.readstring(sformat, path)
+            except IOError:
+                sysexit(4, 'No valid file format provided.')
         else:
             read_file = pybel.readfile(format=sformat, filename=path, opt={"s": None})
-        try:
-            mymol = read_file.next()
-        except StopIteration:
-            sysexit(4, 'File contains no valid molecules.\n')
+            try:
+                mymol = next(read_file)
+            except StopIteration:
+                sysexit(4, 'File contains no valid molecules.\n')
 
         write_message("Molecule successfully read.\n", mtype='debug')
 


=====================================
plip/modules/visualize.py
=====================================
--- a/plip/modules/visualize.py
+++ b/plip/modules/visualize.py
@@ -7,10 +7,10 @@ visualize.py - Visualization of PLIP results using PyMOL.
 from __future__ import absolute_import
 
 # Own modules
-from plip.modules.supplemental import initialize_pymol, start_pymol, write_message, colorlog, sysexit
-import plip.modules.config as config
-from plip.modules.pymolplip import PyMOLVisualizer
-from plip.modules.plipremote import VisualizerData
+from .supplemental import initialize_pymol, start_pymol, write_message, colorlog, sysexit
+from . import config
+from .pymolplip import PyMOLVisualizer
+from .plipremote import VisualizerData
 
 # Python Standard Library
 import json
@@ -29,7 +29,7 @@ def select_by_ids(selname, idlist, selection_exists=False, chunksize=20, restric
     idlist = list(set(idlist))  # Remove duplicates
     if not selection_exists:
         cmd.select(selname, 'None')  # Empty selection first
-    idchunks = [idlist[i:i+chunksize] for i in xrange(0, len(idlist), chunksize)]
+    idchunks = [idlist[i:i+chunksize] for i in range(0, len(idlist), chunksize)]
     for idchunk in idchunks:
         cmd.select(selname, '%s or (id %s)' % (selname, '+'.join(map(str, idchunk))))
     if restrict is not None:


=====================================
plip/modules/webservices.py
=====================================
--- a/plip/modules/webservices.py
+++ b/plip/modules/webservices.py
@@ -5,10 +5,15 @@ webservices.py - Connect to various webservices to retrieve data
 
 # Python standard library
 from __future__ import absolute_import
-import urllib2
+
+try: # Python 3
+    from urllib.request import urlopen
+    from urllib.error import HTTPError
+except ImportError: # Fallback Python 2.x
+    from urllib2 import urlopen, HTTPError
 
 # Own modules
-from plip.modules.supplemental import write_message, sysexit
+from .supplemental import write_message, sysexit
 
 # External libraries
 import lxml.etree as et
@@ -18,7 +23,7 @@ import lxml.etree as et
 def check_pdb_status(pdbid):
     """Returns the status and up-to-date entry in the PDB for a given PDB ID"""
     url = 'http://www.rcsb.org/pdb/rest/idStatus?structureId=%s' % pdbid
-    xmlf = urllib2.urlopen(url)
+    xmlf = urlopen(url)
     xml = et.parse(xmlf)
     xmlf.close()
     status = None
@@ -45,11 +50,11 @@ def fetch_pdb(pdbid):
     write_message('Downloading file from PDB ... ')
     pdburl = 'http://www.rcsb.org/pdb/files/%s.pdb' % current_entry  # Get URL for current entry
     try:
-        pdbfile = urllib2.urlopen(pdburl).read()
+        pdbfile = urlopen(pdburl).read().decode()
         # If no PDB file is available, a text is now shown with "We're sorry, but ..."
         # Could previously be distinguished by an HTTP error
         if 'sorry' in pdbfile:
             sysexit(5, "No file in PDB format available from wwPDB for the given PDB ID.\n")
-    except urllib2.HTTPError:
+    except HTTPError:
         sysexit(5, "No file in PDB format available from wwPDB for the given PDB ID.\n")
     return [pdbfile, current_entry]


=====================================
plip/plipcmd
=====================================
--- a/plip/plipcmd
+++ b/plip/plipcmd
@@ -9,13 +9,13 @@ from __future__ import print_function
 from __future__ import absolute_import
 
 # Own modules
-from plip.modules.preparation import *
-from plip.modules.visualize import visualize_in_pymol
-from plip.modules.plipremote import VisualizerData
-from plip.modules.report import StructureReport,__version__
-from plip.modules import config
-from plip.modules.mp import parallel_fn
-from plip.modules.webservices import check_pdb_status, fetch_pdb
+from modules.preparation import *
+from modules.visualize import visualize_in_pymol
+from modules.plipremote import VisualizerData
+from modules.report import StructureReport,__version__
+from modules import config
+from modules.mp import parallel_fn
+from modules.webservices import check_pdb_status, fetch_pdb
 
 # Python standard library
 import sys
@@ -24,6 +24,7 @@ from argparse import ArgumentParser
 import time
 import multiprocessing
 import json
+
 # External libraries
 import lxml.etree as et
 
@@ -44,14 +45,17 @@ def threshold_limiter(aparser, arg):
 
 
 
-def process_pdb(pdbfile, outpath):
+def process_pdb(pdbfile, outpath, as_string=False):
     """Analysis of a single PDB file. Can generate textual reports XML, PyMOL session files and images as output."""
-    startmessage = '\nStarting analysis of %s\n' % pdbfile.split('/')[-1]
+    if not as_string:
+        startmessage = '\nStarting analysis of %s\n' % pdbfile.split('/')[-1]
+    else:
+        startmessage = "Starting analysis from stdin.\n"
     write_message(startmessage)
     write_message('='*len(startmessage)+'\n')
     mol = PDBComplex()
     mol.output_path = outpath
-    mol.load_pdb(pdbfile)
+    mol.load_pdb(pdbfile, as_string=as_string)
     # #@todo Offers possibility for filter function from command line (by ligand chain, position, hetid)
     for ligand in mol.ligands:
         mol.characterize_complex(ligand)
@@ -79,10 +83,10 @@ def process_pdb(pdbfile, outpath):
             [visualize_in_pymol(plcomplex) for plcomplex in complexes]
 
     if config.XML:  # Generate report in xml format
-        streport.write_xml()
+        streport.write_xml(as_string=config.STDOUT)
 
     if config.TXT:  # Generate report in txt (rst) format
-        streport.write_txt()
+        streport.write_txt(as_string=config.STDOUT)
 
 def download_structure(inputpdbid):
     """Given a PDB ID, downloads the corresponding PDB structure.
@@ -127,13 +131,23 @@ def main(inputstructs, inputpdbids):
     if inputstructs is not None:  # Process PDB file(s)
         num_structures = len(inputstructs)
         inputstructs = remove_duplicates(inputstructs)
+        read_from_stdin = False
         for inputstruct in inputstructs:
-            if os.path.getsize(inputstruct) == 0:
-                sysexit(2, 'Empty PDB file\n')  # Exit if input file is empty
-            if num_structures > 1:
-                basename = inputstruct.split('.')[-2].split('/')[-1]
-                config.OUTPATH = '/'.join([config.BASEPATH, basename])
-            process_pdb(inputstruct, config.OUTPATH)
+            if inputstruct == '-':
+                inputstruct = sys.stdin.read()
+                read_from_stdin = True
+                if config.RAWSTRING:
+                    if sys.version_info < (3,):
+                        inputstruct = bytes(inputstruct).decode('unicode_escape')
+                    else:
+                        inputstruct = bytes(inputstruct, 'utf8').decode('unicode_escape')
+            else:
+                if os.path.getsize(inputstruct) == 0:
+                    sysexit(2, 'Empty PDB file\n')  # Exit if input file is empty
+                if num_structures > 1:
+                    basename = inputstruct.split('.')[-2].split('/')[-1]
+                    config.OUTPATH = '/'.join([config.BASEPATH, basename])
+            process_pdb(inputstruct, config.OUTPATH, as_string=read_from_stdin)
     else:  # Try to fetch the current PDB structure(s) directly from the RCBS server
         num_pdbids = len(inputpdbids)
         inputpdbids =remove_duplicates(inputpdbids)
@@ -157,9 +171,12 @@ if __name__ == '__main__':
 
     parser = ArgumentParser(prog="PLIP", description=descript)
     pdbstructure = parser.add_mutually_exclusive_group(required=True)  # Needs either PDB ID or file
-    pdbstructure.add_argument("-f", "--file", dest="input", nargs="+")
+    pdbstructure.add_argument("-f", "--file", dest="input", nargs="+", help="Set input file, '-' reads from stdin") # '-' as file name reads from stdin
     pdbstructure.add_argument("-i", "--input", dest="pdbid", nargs="+")
-    parser.add_argument("-o", "--out", dest="outpath", default="./")
+    outputgroup = parser.add_mutually_exclusive_group(required=False)  # Needs either outpath or stdout
+    outputgroup.add_argument("-o", "--out", dest="outpath", default="./")
+    outputgroup.add_argument("-O", "--stdout", dest="stdout", action="store_true", default=False, help="Write to stdout instead of file")
+    parser.add_argument("--rawstring", dest="use_raw_string", default=False, action="store_true", help="Use Python raw strings for stdout and stdin")
     parser.add_argument("-v", "--verbose", dest="verbose", default=False, help="Set verbose mode", action="store_true")
     parser.add_argument("-p", "--pics", dest="pics", default=False, help="Additional pictures", action="store_true")
     parser.add_argument("-x", "--xml", dest="xml", default=False, help="Generate report file in XML format",
@@ -173,8 +190,7 @@ if __name__ == '__main__':
                              "If not set, PLIP uses all available CPUs if possible.",
                         type=int)
     parser.add_argument("--breakcomposite", dest="breakcomposite", default=False,
-                        help="Don't combine ligand fragments into with covalent bonds but treat them as single ligands"
-                             "fot the analysis.",
+                        help="Don't combine ligand fragments with covalent bonds but treat them as single ligands for the analysis.",
                         action="store_true")
     parser.add_argument("--altlocation", dest="altlocation", default=False,
                         help="Also consider alternate locations for atoms (e.g. alternate conformations).",
@@ -185,6 +201,9 @@ if __name__ == '__main__':
     parser.add_argument("--nofix", dest="nofix", default=False,
                         help="Turns off fixing of PDB files.",
                         action="store_true")
+    parser.add_argument("--nofixfile", dest="nofixfile", default=False,
+                        help="Turns off writing files for fixed PDB files.",
+                        action="store_true")
     parser.add_argument("--dnareceptor", dest="dnareceptor", default=False,
                         help="Uses the DNA instead of the protein as a receptor for interactions.",
                         action="store_true")
@@ -220,6 +239,8 @@ if __name__ == '__main__':
     config.TXT = arguments.txt
     config.PICS = arguments.pics
     config.PYMOL = arguments.pymol
+    config.STDOUT = arguments.stdout
+    config.RAWSTRING = arguments.use_raw_string
     config.OUTPATH = arguments.outpath
     config.OUTPATH = tilde_expansion("".join([config.OUTPATH, '/'])
                                      if not config.OUTPATH.endswith('/') else config.OUTPATH)
@@ -229,6 +250,7 @@ if __name__ == '__main__':
     config.PEPTIDES = arguments.peptides
     config.INTRA = arguments.intra
     config.NOFIX = arguments.nofix
+    config.NOFIXFILE = arguments.nofixfile
     config.KEEPMOD = arguments.keepmod
     config.DNARECEPTOR = arguments.dnareceptor
     # Assign values to global thresholds


=====================================
plip/test/test_basic_functions.py
=====================================
--- a/plip/test/test_basic_functions.py
+++ b/plip/test/test_basic_functions.py
@@ -77,7 +77,7 @@ class GeometryTest(unittest.TestCase):
         """Generate random data for the tests"""
         # Generate two random n-dimensional float vectors, with -100 <= n <= 100 and values 0 <= i <= 1
         dim = random.randint(1, 100)
-        self.rnd_vec = [random.uniform(-100, 100) for i in xrange(dim)]
+        self.rnd_vec = [random.uniform(-100, 100) for i in range(dim)]
 
     def test_euclidean(self):
         """Tests for mathematics.euclidean"""


=====================================
setup.py
=====================================
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ setup.py - Setup configuration file for pip, etc.
 from setuptools import setup
 
 setup(name='plip',
-      version='1.3.5',
+      version='1.4.0',
       description='PLIP - Fully automated protein-ligand interaction profiler',
       classifiers=[
           'Development Status :: 5 - Production/Stable',
@@ -14,17 +14,19 @@ setup(name='plip',
           'Natural Language :: English',
           'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
           'Programming Language :: Python :: 2.7',
+          'Programming Language :: Python :: 3.5',
           'Topic :: Scientific/Engineering :: Bio-Informatics'
       ],
       url='https://github.com/ssalentin/plip',
       author='Sebastian Salentin',
-      author_email='sebastian.salentin at biotec.tu-dresden.de',
+      author_email='sebastian.salentin at tu-dresden.de',
       license='GPLv2',
       packages=['plip', 'plip/modules'],
       scripts=['plip/plipcmd'],
       install_requires=[
           'openbabel',
           'numpy',
-          'lxml'
+          'lxml',
+          'future'
       ],
       zip_safe=False)



View it on GitLab: https://salsa.debian.org/med-team/plip/compare/b11eaf33a9f454275b0398b2e302ae723bb50511...caf52b101f6144ff869e4eb9b0eb6349578bf44b

---
View it on GitLab: https://salsa.debian.org/med-team/plip/compare/b11eaf33a9f454275b0398b2e302ae723bb50511...caf52b101f6144ff869e4eb9b0eb6349578bf44b
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.alioth.debian.org/pipermail/debian-med-commit/attachments/20180412/c9ee6cfa/attachment-0001.html>


More information about the debian-med-commit mailing list