tdu.Dependency tutorial - 2022-07-31 00:23

tdu.Dependency tutorial

Link to main site

1 Like

this was well laid out. was the siren sounded regarding __del__ functions not running in 2022 TD builds?

I need an example of __del__ functions not running. They work for me in simple cases, so there’s something else going on.

here’s about as simple of an example as i can make. In 2021 builds deleting base1 will properly trigger the debug statement in del, whereas in 2022 builds it doesn’t work.
delExt.toe (4.3 KB)

Okay! That is not the test I was running. Was thinking of a dependency one.

Thank you very much. Will try to get to the bottom of this!

1 Like

Hey, sorry, it was my mistake in the video. Actually everything is working as expected. Here’s the clarification from the video I posted on youtube

“Hey everyone, I actually made a small mistake at 31:30 the reason why the del method was never called was actually because the reference to this object was stored in the callbacks list of another object and therefore garbage collector wasn’t destroying this instance even after re-init. This can be avoided by using something that is called a “weakref”. I uploaded a fixed version of the extension code to the github. so you can compare and see the fix”. td_tutorials/tdu_dependency at main · drum-computer/td_tutorials · GitHub

1 Like

I started to play with __del__ function after seeing this tutorial - @densi thank you very much for making it :slight_smile:. My goal was to try making simple observer pattern in TD and __del__ seemed like a perfect solution for this problem.

However I have noticed that __del__ is only being called when I manually hit extension re-initialization, not when it re-initializes automatically (on code change). @Ivan please may I ask if this is expected behavior?

Send me an example and I can take a look.

Thanks, I am attaching one. When I go inside that base and try to change something in dat viewer, then click somewhere else to stop editing (making the extension update), nothing happens. When I manually click re-initialize, it works.
del.1.toe (4.3 KB)

Hmm I get the del call every time. Attaching my simplified test. Can you tell me exactly the steps to get the extension to update without calling delete? If you can make a movie of it happening that would be awesome. Guess I need your system specs too in case somehow this has to do with that.
del.5.toe (4.0 KB)

When opening your file - del.5.toe, it works for me too. Strangely there is some difference in behavior of del.1.toe and del.5.toe.

I have tried capturing three scenarios, please feel free to take a look at this video. Second scenario didn’t go as expected (bases on my previous tries I have assumed it will work once I delete some parts of extension, but it turned out to be less predictable). Nevertheless I hope it explains a bit better what is happening on my side.

Also I am using latest version in this capture, running on win 10. In case I could help some more please don’t hesitate to tell me what to do :slight_smile:

@Ivan is my example behaving for you properly too?

@drmbt yours is not working and I have that already in the bug queue. The more I can figure out without involving the C++ devs, the faster this stuff bubbles up to get fixed, so working on deciphering @monty_python’s to make it happen faster!

Okay! Between the two examples I was able to find the problem! And the problem is me :grimacing:

Not sure what changed between TouchDesigner and/or Python versions, but in the current setup, both createProperty and StorageManager are keeping a reference to the extension, preventing it from being deleted. This will be fixed in the next release.

Until then, as a workaround, you can use the attached createProperty function. If you need StorageManager it’s a little more complicated but hit me up and I can help with a workaround for that too (989 Bytes)
Thanks for the examples, amigos!


@Ivan thank you very much for help, I am glad you found it :slight_smile:

@densi please may I ask if this scene works for you in latest build? I have spend couple hours trying to make it work with weakref, however without success. Somehow I always end up with having

<weakref at 0x000001C0841FE720; dead>

in dependency callbacks (therefore dependency can’t call specified callbacks). Same thing is happening for me in your scene, so I though I might ask if you are experiencing the same problem? Thanks

I downloaded the tutorial files but it wasn’t clear how to test it. Send me some specific instructions for what you’re trying to achieve and how to get the error and I’ll see what I can figure out.

I looked a bit deeper into the tutorial and found some odd stuff happening for sure, but please do tell me more about what you were trying and about your tests in general.

@Ivan I have tried playing with @densi 's tutorial project files to see how he approached usage of weakref (since I couldn’t get it working for myself). While playing with his project (tdu_dependency.8.toe), I have noticed weakref behaved just the same as it did for me (it wasn’t working in his project either).

Here is my look at that scene (it is essentially doing the same thing as I was trying to do in my tests):

  • MovieBinExtension contains tdu.Dependency _movie_count.
    This dependency is used in MovieListExtenion, where onMovieCountChange is added to callbacks of this dependency (using weakref).

  • Based on this I guess the goal is to make MovieListExtenion an observer, updating itself through onMovieCountChange with every change of data in MovieBinExtension.

  • As it was pointed out, weakref should allow MovieListExtenion objects to be destroyed by gc.

  • To clean up old weakrefs, MovieListExtenion.__del__() removes current object’s weakref from _movie_count.callbacks.
    This means that _movie_count.callbacks should have always only one weakref to MovieListExtenion.onMovieCountChange.

And here is what doesn’t work:

  • weakrefs stored in _movie_count.callbacks are always dead
python >>> op('/project1/movie_bin').MovieCount.callbacks
[<weakref at 0x0000015972844E00; dead>]
  • this means that modifying _movie_count doesn’t produce update of observer
python >>> op('/project1/movie_bin').MovieCount.modified()
Traceback (most recent call last):
  File "<Textport>", line 1
TypeError: __call__() takes at most 0 arguments (1 given)
  • you can also test this by pointing parameter Folder on movie_bin to some folder with videos and hitting Read. movielist_view should update and display your files, but this doesn’t happen as _movie_count.callbacks can’t be called
Traceback (most recent call last):
  File "/project1/movie_bin/parexec1", line 23, in onPulse
  File "/project1/movie_bin/MovieBinExtension", line 41, in OnReadPressed
TypeError: __call__() takes at most 0 arguments (1 given)

I hope this makes sense. :slight_smile: My question would basically be - how could I make non-dead weakref in dependency callbacks?

I see and understand the problem. Looking into a solution for you.