Thanks Joel,
That's really helpful.  Armed with that information, I was able to dig
further into the source code and find some unit tests that do very similar
to what you have set up, but within a context manager.  Hopefully the mail
client won't mangle the formatting.

Cheers,
Dave


#!/usr/bin/env python

import logging

from contextlib import contextmanager
from io import StringIO

from rdkit import rdBase, Chem

@contextmanager
def log_to_python(level=None):
  """
    Temporarily redirect logging to Python streams, optionally
    setting a specific log level.
  """
  rdBase.LogToPythonLogger()
  pylog = logging.getLogger("rdkit")
  if level is not None:
    original_level = pylog.level
    pylog.setLevel(level)

  yield pylog

  if level is not None:
    pylog.setLevel(original_level)
  rdBase.LogToCppStreams()


@contextmanager
def capture_logging(level=None):
  """
    Temporarily redirect logging to a Python StringIO, optionally
    setting a specific log level.
  """
  log_stream = StringIO()
  stream_handler = logging.StreamHandler(stream=log_stream)

  with log_to_python(level) as pylog:
    pylog.addHandler(stream_handler)

    yield log_stream

    pylog.removeHandler(stream_handler)


with capture_logging(logging.WARNING) as log_stream:

    mol = Chem.MolFromSmiles('c1ccccc1(C)(C)')
    print(f'and the message is {log_stream.getvalue()}')
    # this clears the log message.  If you want to keep all the messages
    # as one long string, don't do this.
    log_stream.truncate(0)

    mol = Chem.MolFromSmiles('C(C)(C)(C)(C)C')
    print(f'and now the message is {log_stream.getvalue()}')




On Thu, Feb 1, 2024 at 9:20 PM Joel Duerksen <j...@d2discovery.com> wrote:

> I've changed my strategy a few times. I'll share my most recent approach,
> quite possibly this is flawed, but for now it works for me.  Fixes and
> corrections welcome.
> I think these are all the relevant bits below...
>
> ...
> ... other stuff, import rdkit, etc...
> ...
> # fancy foot work to capture RDKIT messages
> from io import StringIO
> from rdkit import rdBase
> rdBase.LogToPythonLogger()
>
> import logging
> logger = logging.getLogger('rdkit')
> logger.setLevel(logging.WARNING) # make explicit though this is the
> default, currently
>
> ... more code...
> ... I'll show some of the context of how I'm using it..  reading an SDF
> file here, and want to trap every message
>
>         f_in = open_sdf(INPUT_FILE, 'rb')
>         # please don't change the molecule while reading it in
>         suppl = Chem.ForwardSDMolSupplier(f_in, sanitize=False,
> removeHs=False, strictParsing=False)
>
>         with StringIO() as log_stream:
>             log_handler = logging.StreamHandler(log_stream)
>             myLogger = logging.getLogger('rdkit')
>             myLogger.addHandler(log_handler)
>
>             # usually don't pull from a generator this way, but we're
> trying to catch log messages for each molecule individually
>             while True:
>                 try:
>                     # Python 3
>                     log_stream.truncate(0)
>                     log_stream.seek(0)
>                     curmol = next(suppl)
>                 except StopIteration:
>                     break
>
> ... capture everything in the stream from reading the molecule with
> log_stream.getvalue()
>             re.sub(r'\[[0-9]{2}:[0-9]{2}:[0-9]{2}[^]]*\]', '',
> log_stream.getvalue()) # remove the timestamps [12:14:19] (maybe could turn
> them off?)
>
> ... after closing SDF file I'm removing the handler
>         # remove our log handler
>         myLogger.handlers.clear()
>
>
> On Thu, Feb 1, 2024 at 12:49 PM David Cosgrove <davidacosgrov...@gmail.com>
> wrote:
>
>> Hi,
>> I'd like to be able to redirect the various logging streams to files from
>> within the code.  I know that I can turn them off:
>>
>> RDLogger.DisableLog('rdApp.*')
>>
>> but that's more extreme than I want.
>> I have found the function RDLogger.AttachFileToLog() but can't work out
>> how to use it.  The naive
>>
>> RDLogger.AttachFileToLog('rdApp.*', 'logging.file', 1)
>>
>> didn't produce a file anywhere I could see.  I have not been able to find
>> an example of its use.
>>
>> find . -name \*.py -exec grep AttachFileToLog {} \; -print
>>
>> from the top of the source tree produces
>>
>> from rdkit.rdBase import AttachFileToLog, DisableLog, EnableLog,
>> LogMessage
>> ./rdkit/RDLogger.py
>>
>> but the functions don't seem to be used within that file.
>>
>> Any pointers gratefully received.
>> Dave
>>
>>
>> --
>> David Cosgrove
>> Freelance computational chemistry and chemoinformatics developer
>> http://cozchemix.co.uk
>>
>> _______________________________________________
>> Rdkit-discuss mailing list
>> Rdkit-discuss@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/rdkit-discuss
>>
>
>
> --
> Regards,
>      Joel
>
> ----
> *Joel L. Duerksen     *j...@d2discovery.com
> *Innovative Machine Learning and Data Science Solutions*
>
>

-- 
David Cosgrove
Freelance computational chemistry and chemoinformatics developer
http://cozchemix.co.uk
_______________________________________________
Rdkit-discuss mailing list
Rdkit-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rdkit-discuss

Reply via email to