I've noticed a flawed implementation in the current Extension code (written and messed up by myself ). The problem comes from the python side of things. I've made a bug report issue #4534 and here is the detailed description:
Adding a python extension creates the ExtensionProxy property, which is set to the default value passed in the addExtension method. This property belongs to the extension (defined here), and is exposed as an property for the object. The problem arises when a second python extension is added to the same object. In FC the extension itself gets the ExtensionProxy setup correctly in the addExtension method, as this method directly accesses the extension to get the property (see). However, now there are two ExtensionProxy' properties in the object, one for each extension. Accessing it from python will return only one, the first one that is found (see here).
This leads to the FreeCAD bug, that you cannot change the ExtensionProxy correctly for more than one extension. Note that neither in 0.18 or 0.19 this ever occured as bug, as no one seem to use more than 1 extension and also not the ExtensionProxy and just rely on addExtension. However, it could lead to all kind of unexpected behavior later.
Reproduce:
Code: Select all
class Proxy1():
def init(self):
pass
class Proxy2():
def init(self):
pass
p1 = Proxy1()
p2 = Proxy2()
obj = App.ActiveDocument.addObject("App::DocumentObject", "MyObject")
obj.addExtension("App::GroupExtensionPython", p1)
obj.addExtension("Part::AttachExtensionPython", p2)
print(f"ExtensionProxy is Proxy1: {isinstance(obj.ExtensionProxy, Proxy1)}")
print(f"ExtensionProxy is Proxy2: {isinstance(obj.ExtensionProxy, Proxy2)}")
Now to be honest adding the ExtensionProxy to the extension was a stupid idea, and I think this approach is fundamentally flawed. There needs to be a single proxy for all python extensions to avoid any ambiguity. As the extensions are already in FC0.18 some thougth about backward compatibility are required.
Solution 1: Add ExtensionProxy to FeaturePython
This is the simplest fix, just remove extension proxy from all python extensions and make it a default property for FeaturePython. Than all extensions access their objects Extension proxy. I think this should keep all file compatibility. I did not find any use of two extensions in a object, hence unifying them should not make any trouble. However, there could theoretically be some code out there not working with this unification.
Solution 2: Drop ExtensionProxy and use the normal python Proxy instead.
It turns out that no one uses ExtensionProxy property for anything, currently the proxys are all set within the addExtension method. Furthermore I did not find any instance in FreeCAD source where Proxy != ExtensionProxy. Hence one can simply drop the property and use the normal python Proxy instead. This is a small problem for file compatibility, as loading old files need to drop a property. Also it could lead to some additional problems in external code when ExtensionProxy != Proxy.
Problems:
Both Solutions make some incompatible design changes as described in the individual solutions. Additionally the "addExtension" method would need to change, and the second extensionproxy argument needs to be dropped. This of course is used on FC and some addons. So one could either remove the second argument fully, and let everyone change the code. Or maybe for now make it optional and just ignore the argument and print a deprecation method for the next release (easier for developers, more annoying for users seeing it)
Summary: Qestions to be answered
- Should the problem be solved or keept as is for minimal impact on external code?
- Use unified ExtensionProxy or general Proxy property?
- Change addExtension to be incompatible to 0.18 or use deprication warning?
- Any better Solutions I've overlooked?
Regards,
Stefan