Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple calls to BlockLogs() permanently disable logging #5172

Closed
ricrogz opened this issue Apr 6, 2022 · 5 comments · Fixed by #5181
Closed

Multiple calls to BlockLogs() permanently disable logging #5172

ricrogz opened this issue Apr 6, 2022 · 5 comments · Fixed by #5181
Assignees
Labels
Milestone

Comments

@ricrogz
Copy link
Contributor

ricrogz commented Apr 6, 2022

Found with Release 2020_03_1b1:

In [3]: Chem.MolFromSmiles('garbage')                                                                                                                        
[11:49:29] SMILES Parse Error: syntax error while parsing: garbage
[11:49:29] SMILES Parse Error: Failed parsing SMILES 'garbage' for input: 'garbage'

In [4]: def blocklogs(): 
   ...:     b = Chem.rdBase.BlockLogs() 
   ...:     b = Chem.rdBase.BlockLogs() 
   ...:                                                                                                                                                      

In [5]: blocklogs()                                                                                                                                          

In [6]: Chem.MolFromSmiles('garbage')                                                                                                                        

In [7]:  

This is relevant because we do actually call BlockLogs() multiple times in places like

def _moltoimg(mol, sz, highlights, legend, returnPNG=False, drawOptions=None, **kwargs):
try:
blocker = rdBase.BlockLogs()
mol.GetAtomWithIdx(0).GetExplicitValence()
except RuntimeError:
mol.UpdatePropertyCache(False)
kekulize = _okToKekulizeMol(mol, kwargs.get('kekulize', True))
wedge = kwargs.get('wedgeBonds', True)
try:
blocker = rdBase.BlockLogs()
mc = rdMolDraw2D.PrepareMolForDrawing(mol, kekulize=kekulize, wedgeBonds=wedge)
except ValueError: # <- can happen on a kekulization failure

@ricrogz ricrogz added the bug label Apr 6, 2022
@greglandrum
Copy link
Member

It's actually even more entertaining and random than that:

In [4]: bl = rdBase.BlockLogs()

In [5]: Chem.MolFromSmiles('c1cc')

In [6]: bl = None

In [7]: Chem.MolFromSmiles('c1cc')
[15:52:20] SMILES Parse Error: unclosed ring for input: 'c1cc'

In [8]: bl = rdBase.BlockLogs()

In [9]: Chem.MolFromSmiles('c1cc')

In [10]: bl2 = rdBase.BlockLogs()

In [11]: Chem.MolFromSmiles('c1cc')

In [12]: bl = None

In [13]: Chem.MolFromSmiles('c1cc')
[15:52:42] SMILES Parse Error: unclosed ring for input: 'c1cc'

In [14]: bl2 = None

In [15]: Chem.MolFromSmiles('c1cc')

In [16]: bl = rdBase.BlockLogs()

In [17]: Chem.MolFromSmiles('c1cc')

In [18]: bl = None

In [19]: Chem.MolFromSmiles('c1cc')

@greglandrum
Copy link
Member

greglandrum commented Apr 7, 2022

Ok, this happens because BlockLogs() creates a LogStateSetter object which captures the current state of the logs. When the object is destroyed that status is restored.
So the first time you call BlockLogs() it stores the current status.
Then the second time stores "all logs disabled"
So if the second object is destroyed second then the status is left as "all logs disabled"
sigh

@ricrogz
Copy link
Contributor Author

ricrogz commented Apr 7, 2022

Yeah, that is what happens if you store both BlockLogs() on the same variable: the second instance gets created before the first is destroyed. Then, it gets assigned to the var, and the first is destroyed, and what you mentioned happens.

If you assign the BlockLogs() to different variables, and then leave the context... race condition, depending on which one gets cleaned up by the garbage collector?

Should we make LogStateSetter() a singleton, so that we can only have one instance at a time, and always restore to the first state?

@bp-kelley
Copy link
Contributor

bp-kelley commented Apr 7, 2022 via email

@greglandrum
Copy link
Member

I think the solution is simpler. For BlockLogs, we should only save the state of logs that were initially enabled. I.e. only save the state of logs we toggled to block. Cheers, Brian

I like this solution...

@ricrogz ricrogz self-assigned this Apr 9, 2022
@ricrogz ricrogz mentioned this issue Apr 9, 2022
@greglandrum greglandrum added this to the 2022_03_2 milestone Apr 12, 2022
greglandrum pushed a commit that referenced this issue Apr 12, 2022
* add test

* fix LogStateSetter

* fix BlockLogs() usage in Draw module

* allow BlockLogs() as a contestmgr

* move test to more suitable location

* guarantee log restoration on __exit__

* skip test if logs cannot be grabbed before block
greglandrum pushed a commit that referenced this issue Apr 25, 2022
* add test

* fix LogStateSetter

* fix BlockLogs() usage in Draw module

* allow BlockLogs() as a contestmgr

* move test to more suitable location

* guarantee log restoration on __exit__

* skip test if logs cannot be grabbed before block
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants