Hi Mike,

please find here a solution which I have just tested and works well on both Unix and Windows.

You need to redirect the C++ stderr stream with ctypes around the call whose output you wish to grab.

This can be done defining a context manager that uses ctypes:

import os
import sys
import datetime
import ctypes
import io
import tempfile
from contextlib import contextmanager

# Adapted from
# https://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/
if (sys.platform == "win32"):
    kernel32 = ctypes.WinDLL("kernel32")
    # https://docs.microsoft.com/en-us/windows/console/getstdhandle
    C_STD_ERROR_HANDLE = -12
    c_stderr = kernel32.GetStdHandle(C_STD_ERROR_HANDLE)
    c_flush = kernel32.FlushFileBuffers
else:
    libc = ctypes.CDLL(None)
    c_stderr = ctypes.c_void_p.in_dll(libc, "stderr")
    c_flush = libc.fflush

@contextmanager
def stderr_redirector(stream):
    # The original fd stderr points to.
    original_stderr_fd = sys.stderr.fileno()

    def _redirect_stderr(to_fd):
        """Redirect stderr to the given file descriptor."""
        # Flush the C-level buffer stderr
        c_flush(c_stderr)
        # Flush and close sys.stderr - also closes the file descriptor (fd)
        sys.stderr.close()
        # Make original_stderr_fd point to the same file as to_fd
        os.dup2(to_fd, original_stderr_fd)
        # Create a new sys.stderr that points to the redirected fd
        sys.stderr = io.TextIOWrapper(os.fdopen(original_stderr_fd, 'wb'))

    # Save a copy of the original stderr fd in saved_stderr_fd
    saved_stderr_fd = os.dup(original_stderr_fd)
    try:
        # Create a temporary file and redirect stderr to it
        tfile = tempfile.TemporaryFile(mode='w+b')
        _redirect_stderr(tfile.fileno())
        # Yield to caller, then redirect stderr back to the saved fd
        yield
        _redirect_stderr(saved_stderr_fd)
        # Copy contents of temporary file to the given stream
        tfile.flush()
        tfile.seek(0, io.SEEK_SET)
        stream.write(tfile.read())
    finally:
        tfile.close()
        os.close(saved_stderr_fd)

Then, all you need to grab the RDKit warning printed to stderr is use the stderr_redirector() context manager around the relevant call, then check the grabbed output for relevant content.

For instance, in your example wrap the Chem.MolToInchi() call as follows:

              f = io.BytesIO()
              with stderr_redirector(f):
                  InChi = Chem.MolToInchi(Chem.MolFromSmiles(y))
              grabbed_stderr = f.getvalue().decode('utf-8')
              if ("WARNING" in grabbed_stderr):
                  print("caught: ", grabbed_stderr)

Cheers,
p.

On 09/10/2019 18:10, Mike Mazanetz wrote:

Hi,

Many thanks this, it is very helpful to see some code.

Yes, as it stands, I am yet to get warnings which are seen in stdout being sent to a file, only errors seem to find their way to my files.

Usually Warnings about stereochemistry don’t get captured.  Anyone see this, I’m guessing it’s the same for failed InChI’s too?

Thanks,

mike

*From:*Scalfani, Vincent <vfscalf...@ua.edu>
*Sent:* 09 October 2019 14:40
*To:* Maciek Wójcikowski <mac...@wojcikowski.pl>; Greg Landrum <greg.land...@gmail.com>
*Cc:* RDKit Discuss <rdkit-discuss@lists.sourceforge.net>
*Subject:* Re: [Rdkit-discuss] Inchi which flavour??

Hi Macjek and Mike,

If I understand your question correctly, you can specify InChI option parameters when calculating InChIs. Here is an example:

m = Chem.MolFromSmiles('CCC1=CN=C(NC1=O)NC')

Chem.MolToInchi(m)

'InChI=1S/C7H11N3O/c1-3-5-4-9-7(8-2)10-6(5)11/h4H,3H2,1-2H3,(H2,8,9,10,11)'

Now, try with one of the non-standard options such as FixedH:

Chem.MolToInchi(m,'/FixedH')

'InChI=1/C7H11N3O/c1-3-5-4-9-7(8-2)10-6(5)11/h4H,3H2,1-2H3,(H2,8,9,10,11)/f/h8,10H'

To answer the question of what happens when the InChI calculation fails, I get an empty string.

m = Chem.MolFromSmiles('[C@H]1([C@H](C1C2[C@@H]([C@@H]2C(=O)O)C(=O)O)C(=O)O)C(=O)O')

Chem.MolToInchi(m)

'  '

There is also an InChI option that can warn on empty structures, and calculate an empty InChI, which I am assuming is supposed to be ‘InChI=1S//’, however, when trying this option I get the same result as above.

Chem.MolToInchi(m,'/WarnOnEmptyStructure')

'  '

I hope that helps.

Vin

*From:*Maciek Wójcikowski <mac...@wojcikowski.pl <mailto:mac...@wojcikowski.pl>>
*Sent:* Wednesday, October 9, 2019 3:41 AM
*To:* Greg Landrum <greg.land...@gmail.com <mailto:greg.land...@gmail.com>> *Cc:* RDKit Discuss <rdkit-discuss@lists.sourceforge.net <mailto:rdkit-discuss@lists.sourceforge.net>>
*Subject:* Re: [Rdkit-discuss] Inchi which flavour??

Mike,

On top of what Greg said what might be particularly useful is an options parameter where you can pass some non default params to InChI call.

śr., 9 paź 2019, 07:22 użytkownik Greg Landrum <greg.land...@gmail.com <mailto:greg.land...@gmail.com>> napisał:

    Hi Mike,

    The InChI API itself is not exposed. The contents of the
    module are in the documentation along with some explanations of
    how to call it:

    http://rdkit.org/docs/source/rdkit.Chem.rdinchi.html

    If something is missing there, please let us know.

    -greg

    On Tue, Oct 8, 2019 at 5:20 PM <mi...@novadatasolutions.co.uk
    <mailto:mi...@novadatasolutions.co.uk>> wrote:

        Dear RdKit users,

        I was reading the inchi module docs and I couldn't find
        methods to call the InChI API.  Are these exposed in RDKit?

        It says the default is the standard Inchi.  What happens when
        this conversion fails?

        Thanks,

        Mike

        _______________________________________________
        Rdkit-discuss mailing list
        Rdkit-discuss@lists.sourceforge.net
        <mailto:Rdkit-discuss@lists.sourceforge.net>
        https://lists.sourceforge.net/lists/listinfo/rdkit-discuss

    _______________________________________________
    Rdkit-discuss mailing list
    Rdkit-discuss@lists.sourceforge.net
    <mailto:Rdkit-discuss@lists.sourceforge.net>
    https://lists.sourceforge.net/lists/listinfo/rdkit-discuss



_______________________________________________
Rdkit-discuss mailing list
Rdkit-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rdkit-discuss
_______________________________________________
Rdkit-discuss mailing list
Rdkit-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rdkit-discuss

Reply via email to