[Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Thu Sep 10, 2020 1:32 am Can you elaborate how you uses these two attributes in the original FeaturePython? If you need to save those attributes to document, then you can simply addProperty to link. If it is only for runtime use, just create a bigger dictionary in the original FeaturePython and key on link. You can include original object as key too,

Code: Select all

	self.links[linkObj] = ({}, '')
	
	#or use more fancy objects like namedtuple and default dict
	# MyStorage = namedtuple('MyStorage', ('objDict', 'objTag'), defaults=({}, ''))
	
	self.links = defaultdict(MyStorage)
	
	# then simply use it like
	self.links[linkObj].objDict.get('something')
Thanks ! Something like below ? :)

Code: Select all

>>> LinkedObject.Proxy.links={}
>>> Link.Name
'Link'
>>> LinkedObject.Proxy.links[Link]=({},'')
...
>>> LinkedObject.Proxy.links[Link][0]
{'2f112fc5-57b4-4034-ab17-0e8da7d328af': {'index': 0}, 'bd1e063d-a95e-4a39-96c6-1e458bde9454': {'index': 1}}


PropertyPythonObject::toString(): failed for <class 'ArchSketchObject.ArchSketch'>
Traceback (most recent call last):
  File "/home/paullee/Downloads/FreeCAD_0.19-21329-Linux-Conda_glibc2.12-x86_64/squashfs-root/usr/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/home/paullee/Downloads/FreeCAD_0.19-21329-Linux-Conda_glibc2.12-x86_64/squashfs-root/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/home/paullee/Downloads/FreeCAD_0.19-21329-Linux-Conda_glibc2.12-x86_64/squashfs-root/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
<class 'TypeError'>: keys must be str, int, float, bool or None, not App.DocumentObject
There seems to be 2 problems -
  1. The dict containing DocumentObject can't be saved to file ?
  2. Wondering : The dict rely on the the Link Object as a key. If the original Link Object is somehow deleted, the dict entry is not deleted to my understanding. Then, when a new Link is formed, the value with the key of original Link would be wrongly be associated with the new Link Object ? ... searching how to test a Dict entry for the Link object has existed ...?
The {} is supposedly contains Sketch.Geometry.Tag etc. to trace which edge to 'attach' / calculate the placement.

Code: Select all

{'2f112fc5-57b4-4034-ab17-0e8da7d328af': {'index': 0}, 'bd1e063d-a95e-4a39-96c6-1e458bde9454': {'index': 1}}
And Feature Python e.g. in Arch WB has

Code: Select all

        self.Type = "Wall"
        # "ArchSketch" in my test
Haven't learnt namedtuple(), defaultdict() yet, let's leave it in the meantime :oops:
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

paullee wrote: Thu Sep 10, 2020 8:58 pm [*]The dict containing DocumentObject can't be saved to file ?
[*]Wondering : The dict rely on the the Link Object as a key. If the original Link Object is somehow deleted, the dict entry is not deleted to my understanding. Then, when a new Link is formed, the value with the key of original Link would be wrongly be associated with the new Link Object ? ... searching how to test a Dict entry for the Link object has existed ...?
That's why I ask whether you want to save the attribute to file. If you do, then you must use any of the PropertyLink derived property to store document object link. You can't store the document object in other python object and hoping it can restore. You can add a PropertyLink to Link for this purpose.

If you do not need to save those attributes, like you can somehow rebuild them when restore, then it is safe to use the Python FreeCAD document object as key. Python use the object id to compute hash, and internally this id is just the python object's memory address. Even if the C++ document object is deleted, its Python binding object still lives because of reference counting. As long as you don't try to access the document object attributes, like Name, it is safe to use. When a new Link is created, of course it will have its own Python binding object, and it will be a new key.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Sat Sep 12, 2020 12:13 am That's why I ask whether you want to save the attribute to file. If you do, then you must use any of the PropertyLink derived property to store document object link. You can't store the document object in other python object and hoping it can restore. You can add a PropertyLink to Link for this purpose.

If you do not need to save those attributes, like you can somehow rebuild them when restore, then it is safe to use the Python FreeCAD document object as key. Python use the object id to compute hash, and internally this id is just the python object's memory address. Even if the C++ document object is deleted, its Python binding object still lives because of reference counting. As long as you don't try to access the document object attributes, like Name, it is safe to use. When a new Link is created, of course it will have its own Python binding object, and it will be a new key.
Thanks mentoring :D

Yes, have a PropertyLink already. I just previously learn to add a dict in (original Linked) Feature Python like -

Code: Select all

self.DictForPropertyLinkObject = {}
Now if the Links can't do similar, scratching my head how to add a dict in (original Linked) Feature Python to do that for each and every Links....

Would experiment trial and error to see how things works.

Thanks in the meantime !
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

BTW, share video of mockup to illustrate what is trying to achieved.

With Links to the Door, hope each Link of Door could have its own placement in the wall :)

phpBB [video]



phpBB [video]
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

paullee wrote: Sat Sep 12, 2020 4:14 am Now if the Links can't do similar, scratching my head how to add a dict in (original Linked) Feature Python to do that for each and every Links....

Would experiment trial and error to see how things works.

Thanks in the meantime !
Not sure why you want that dict to be stored in Link. The "dict using Link as key" idea should be able to work. However, if you really want to add some python object as property to Link, you can. Simply do link.addProperty('App::PropertyPythonObject', 'SomeName'). And you can now assign any python object to link.SomeName. But like I said, anything involving document object cannot be restored with normal Python objects. You can explicitly set the property to not save to document, using link.setPropertyStatus('SomeName', 'Transient'), and rebuild the value later on.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Sat Sep 12, 2020 9:05 am Not sure why you want that dict to be stored in Link. The "dict using Link as key" idea should be able to work. However, if you really want to add some python object as property to Link, you can. Simply do link.addProperty('App::PropertyPythonObject', 'SomeName'). And you can now assign any python object to link.SomeName. But like I said, anything involving document object cannot be restored with normal Python objects. You can explicitly set the property to not save to document, using link.setPropertyStatus('SomeName', 'Transient'), and rebuild the value later on.
Wow, never realised the purpose of this property and it works to add a dict etc. :!:

Just wonder if a Scripted Object / Python Feature can do something like below that can be saved in file -

Code: Select all

self.dict = {}
Why there is a property for the document object... any difference in practice ?

Code: Select all

fp.addProperty('App::PropertyPythonObject', 'dict')
fp.dict = {}
Just curious to understand the design of FC
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

paullee wrote: Sun Sep 13, 2020 5:43 am Just wonder if a Scripted Object / Python Feature can do something like below that can be saved in file -

Code: Select all

self.dict = {}
PropertyPythonObject uses Python pickle to dump the object to json for saving. So any Python object that supports pickle can be saved. This is how FreeCAD supports using Python to extend existing C++ document objects, by using a PropertyPythonObject property named as 'Proxy'. The extendable native C++ object (e.g. App::FeaturePython) will call various Python Proxy API (all of which are optional) to support custom behavior. That's what I mean when I mentioned extension through Proxy. You can define functions like execute(), onChanged(), etc in your Proxy object to be called by the native object.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Sun Sep 13, 2020 11:57 pm ping
Thanks for creating this feature and helping :D Almost finished implementing and seems find a final step not knowing how to make it works, simplified as follows :-

Code: Select all

def updateAttachmentOffset(fp, linkFp=None):

    if linkFp:
        print (" linkFp ... ")
        fp = linkFp
        tempAttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(2000,500,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
    else:
        print (" fp ... ")
        tempAttachmentOffset = FreeCAD.Placement(FreeCAD.Vector(0,500,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))

    fp.AttachmentOffset = tempAttachmentOffset
Full ArchSketchObject.py attached

Expectation
  1. Above code I supposedly should set a LinkedObject at Placement A
  2. while should set a Link at Placement B

Outcome
  1. Recompute the Linked Object (a SketchObjectPython object)
    (ArchSketch__Test_Dependent__00 in test file, attached)
  2. Linked Object set to Placement A - No Problem
    (p.s. Found the Links also set to Placement A in fact, but do not move !?)
    ...
  3. Recompute the Link
    (ArchSketch__Test_Dependent__01)
  4. Link Do Not Move !!!
  5. Linked Object set to Placement B !!!
  6. Though find Both Link + Linked Object set to Placement B !!!
    ...
  7. 16324.2 <App> Document.cpp(3455): Test__Link_appLinkExecute__02#ArchSketch063 still touched after recompute
Thanks for any idea !

[EDIT]
p.s.
It seems Attachment Offset is not simply part of Placement - only shown when there is MapMode - and can't simply add in Link:
- linkFp.addProperty("App::PropertyPlacement","AttachmentOffset","Test","For Link")
to 'supersede' Linked Object's Attachment Offset ...

Screenshot from 2020-09-17 01-42-54.png
Screenshot from 2020-09-17 01-42-54.png (240.25 KiB) Viewed 2336 times
Screenshot from 2020-09-17 01-42-17.png
Screenshot from 2020-09-17 01-42-17.png (241.73 KiB) Viewed 2336 times
Screenshot from 2020-09-17 01-56-37.png
Screenshot from 2020-09-17 01-56-37.png (243.04 KiB) Viewed 2336 times
Attachments
ArchSketchObject.py
(1.06 KiB) Downloaded 66 times
Test_ Link_appLinkExecute_ 02.FCStd
(235.59 KiB) Downloaded 90 times
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

The 'AttachmentOffset' property belongs to the AttachExtension. You can't just manually add this property to an object and hope the attachment will work. You need to install it using the following code.

Code: Select all

if not linkObj.hasExtension('Part::AttachExtension'):
	linkObj.addExtension('Part::AttachExtensionPython', None)
Once you install the extension, linkObj will have its own 'AttachmentOffset' attribute. Note that, there is a pending PR fixing a relating bug, which also exists in my current release as well. You'll have to wait for it to be merged before you can test installing extension. Or, you can manually apply the PR and compile it yourself.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
paullee
Veteran
Posts: 5097
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Fri Sep 18, 2020 1:21 pm The 'AttachmentOffset' property belongs to the AttachExtension. You can't just manually add this property to an object and hope the attachment will work. You need to install it using the following code.

Code: Select all

if not linkObj.hasExtension('Part::AttachExtension'):
	linkObj.addExtension('Part::AttachExtensionPython', None)
I see, have briefly read something about this earlier, will dig out to read again, seem needs one or two lines of code in execute() maybe.

Many thanks all the information indeed !
Post Reply