open_toontown_panda3d/tests
rdb 38692dd525 interrogate: Support subclassing C++ objects from Python
This change enables persistent Python wrapper objects for Python subclasses of typed, reference counted C++ objects.  That means that these objects will store a reference to `self` on the C++ object, and interrogate will always return that instead of making a new Python wrapper every time it is returned from C++.

Practically, this means that you could subclass eg. PandaNode, Event, Fog, what have you, and store these in the scene graph - the Python data in the subclass will be retained and Panda will return your subclass when you ask for the object back rather than creating a new wrapper object without your original data.

To do this, Interrogate generates a proxy class inheriting from the C++ type with additional room to store a `self` pointer and a TypeHandle (which is returned by an overridden `get_type()`).  This TypeHandle is automatically created by registering the Python subclass with the typing system.  The proxy class is only used when the constructor detects that it's constructing for a subtype, so that regular uses of the C++ type are not affected by this mechanism.

(The registration with the typing system could use some improvement.  There's no regard for namespacing right now, in particular.  Furthermore, we could move the registration to an `__init_subclass__()` method, with parameters to specify an existing TypeHandle or to customize the type name.)

This creates a reference cycle, which must be cleared somehow.  One way this happens is by overriding `unref()` in the proxy, which checks that if the Python and C++ reference counts are both 1, this must be the circular reference, and then it breaks the cycle.  Note that this will _only_ work if all other Python references have been cleared before the last C++ reference goes away.  For the other case, we need to rely on Python's garbage collector, so these classes also implement tp_traverse and tp_clear.

This commit also therefore re-enables Python garbage collector support (ie. defining `__traverse__()`), which was previously disabled due to the problems caused by multiple Python wrappers referring to the same C++ object.  To avoid these problems, Panda will only cooperate with Python's GC if the C++ reference count is 1, in which case we can trivially prove that the last reference must be from the Python wrapper.  Note that this explains why we need persistent wrappers for traversal to work--if there are multiple Python wrappers pointing to the C++ object, and they are all participating in a reference cycle, the reference count cannot be 1, and cycle detection does not work.  By default, the GC is only enabled for Python subclasses, but a class may define `__traverse__()` in order to opt-in, keeping the previous limitation in mind.

There is a second mechanism introduced by this commit: classes may define a public `__self__` member of type `PyObject *` if they want to use persistent objects even if they aren't being subclassed.  This allows these classes to participate in Python's GC and avoid the situation above.

The cycle detection is implemented for PandaNode's Python tags, but this is very incomplete, since the traversal doesn't recurse into children and it won't work if there is more than one wrapper object that is part of a cycle, since PandaNode by default doesn't use persistent wrappers.  This problem may need more attention later.

Fixes #1410
2024-03-29 20:51:34 +01:00
..
audio tests: Update audio test to recognize missing sounds as NullAudioSound 2018-02-20 00:55:49 -07:00
bullet Merge branch 'release/1.10.x' 2022-06-29 19:09:59 +02:00
collide collide: Add CollisionHeightfield solid (#691) 2023-08-05 21:14:52 +02:00
dcparser tests: add some DCPacker unit tests (for #751) 2019-12-25 16:58:11 +01:00
directnotify directnotify: annotate types (#1527) 2023-10-09 09:46:32 +02:00
display Merge branch 'release/1.10.x' 2024-01-04 16:36:03 +01:00
dist Merge branch 'release/1.10.x' 2023-10-15 23:02:47 +02:00
distributed Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
dtoolutil Remove support for EOL Python versions 3.6 and 3.7 2023-08-04 14:20:59 +02:00
egg egg: add ability to read <Tangent> with four components 2019-02-05 00:30:54 +01:00
egg2pg tests: attempt to fix egg2pg test failure on macOS 2018-08-19 16:49:54 +02:00
event interrogate: Support subclassing C++ objects from Python 2024-03-29 20:51:34 +01:00
express tests: Skip encrypt_string test when building without OpenSSL 2023-02-22 23:31:32 +01:00
fsm Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
gobj tests: Don't rely on png being available for TexturePool tests 2023-02-24 23:01:40 +01:00
gui Merge branch 'release/1.10.x' 2024-01-23 16:56:38 +01:00
interrogate tests: Remove executable permissions from test_property.py 2023-02-22 18:20:39 +01:00
linmath linmath: Implement read-only buffer protocol support for vectors 2021-10-27 10:53:35 +02:00
mathutil tests: Add new unit test for Triangulator (also testing #985) 2020-08-18 18:38:19 +02:00
movies tests: Added video and audio tests 2023-02-07 18:08:32 +01:00
ode ode: fix OdeJoint.attach with None parameters 2019-04-28 22:29:29 +02:00
particles Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
pgraph interrogate: Support subclassing C++ objects from Python 2024-03-29 20:51:34 +01:00
physics Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
pipeline tests: Switch from deprecated ConditionVarFull to ConditionVar 2022-02-22 15:22:10 +01:00
pnmimage pnmimage: Added offset to add_sub_image and mult_sub_image 2020-04-25 22:56:40 +02:00
prc Merge commit 'e0d34131822a8852ff72dc9c5597f4dc6900719a' 2020-09-13 16:17:06 +02:00
putil Squash merge webgl-port branch into master 2024-01-25 15:37:38 +01:00
showbase tests: Fix an issue running tests with some Python 3.4 setups 2023-10-15 16:21:30 +02:00
stdpy Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
task task: Annotate core functions (#1548) 2023-10-13 21:20:20 +02:00
text tests: add unit test for TextNode::write, see #431 2018-10-28 11:45:39 +01:00
tform tform: MouseWatcher sort should uniquify duplicates 2018-06-12 13:44:24 +02:00
tkpanels tests: Don't run tkpanels.Placer test without Tk already inited 2023-10-14 20:07:35 +02:00
tkwidgets Move test code from across `direct` to proper test modules 2023-08-02 08:37:51 +02:00
build_samples.py tests/build_samples: Use temporary directories to avoid in-source builds 2019-01-04 18:55:31 -08:00
conftest.py tests: Don't require tkinter to be able to run test suite 2023-08-05 10:29:32 +02:00
main.py deploy-ng: Add files to build application out of the unit tests 2017-11-25 17:36:02 -08:00
requirements.txt workflow: Add setuptools as requirement when testing Python 3.12 2023-10-14 11:29:02 +02:00
run_mypy.py tests: Don't expect mypy to be on the system PATH 2023-10-22 10:39:41 +02:00
setup.py tests: fix syntax error in setup.py, use default platforms 2018-12-28 15:36:02 +01:00
test_imports.py tests: Add unit test to check new panda3d.net module 2024-03-02 13:41:23 +01:00
test_tools.py tests: Further expand on tools tests 2023-08-03 13:21:38 +02:00