gaogaotiantian / watchpoints

watchpoints is an easy-to-use, intuitive variable/object monitor tool for python that behaves similar to watchpoints in gdb.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AttributeError: 'NoneType' object has no attribute 'exists'

dvirtz opened this issue · comments

import os
from watchpoints import watch

os.environ['a'] = 'before'
watch(os.environ)
os.environ['a'] = 'after'

results in

====== Watchpoints Triggered ======
Call Stack (most recent call last):
Exception ignored in: <async_generator object _ag at 0x7feacd0fc320>
Traceback (most recent call last):
  File "/usr/lib64/python3.6/types.py", line 27, in _ag
  File "/home/conan/.local/lib/python3.6/site-packages/watchpoints/watch.py", line 133, in tracefunc
  File "/home/conan/.local/lib/python3.6/site-packages/watchpoints/watch.py", line 158, in _default_callback
  File "/home/conan/.local/lib/python3.6/site-packages/watchpoints/watch_print.py", line 36, in __call__
  File "/home/conan/.local/lib/python3.6/site-packages/watchpoints/watch_print.py", line 48, in _file_string
  File "/home/conan/.local/lib/python3.6/site-packages/watchpoints/watch_print.py", line 56, in getsourceline
AttributeError: 'NoneType' object has no attribute 'exists'

Sorry I used the wrong code. I'll look into it

Sorry I noticed that I'm using the wrong code. I'm looking into it. It seems like a resource release error. Could you try to unwatch at the end of your code and see if you could reproduce it?

import os
from watchpoints import watch, unwatch

watch(os.environ)
os.environ['a'] = 'after'
unwatch(os.environ)

does not error but neither it triggers the watchpoint

Yeah, I'm looking into it and see why it won't trigger the watchpoint.

Oh I see what's going on for the watchpoint not trigger issue.

os.environ is a customized object(os._Environ). For customized objects, there is no way for watchpoints to reliably figure out if it's changed, or copy it. The best it can do is to guess. So, by default, it will create a shallow copy of the object and use __eq__(!=) method for comparison.

For this matter, when you watch os.environ, a shallow copy is not enough to make watchpoints aware of the changes, because the copy watchpoints saved will be changed as well when you do os.environ['a'] = "after".

This is not a bug, but a trade off for default behavior. One simple solution is to use deepcopy.

watch(os.environ, deepcopy=True)

Or you can define your own copy method of the object and pass it with copy arg:

watch(os.environ, copy=your_own_copy_function).

The exception is still a bug, but let me know if this trigger explanation is good for you.

I believe the exception was an issue to access stuff when python try to release the objects(at the end of the execution). For now I don't think it's meaningful or possible to monitor variables in this process reliably. I will just turn watchpoints off when the main body of script is done with atexit.