how to identify my Part::FeaturePython objects

Need help, or want to share a macro? Post here!
emills2
Posts: 593
Joined: Tue Apr 28, 2015 11:23 pm

how to identify my Part::FeaturePython objects

Post by emills2 » Sun Dec 29, 2019 1:14 am

I have not yet found a clean way to identify my various Part::FeaturePython objects after creating them, and i wonder what the most direct way is.

ideally, i would receive "ControlGrid44_4" when checking "TypeId", but i receive a generic 'Part::FeaturePython'.

i could use the truncated object name to check against, but that feels clumsy

i really wish i could get the string portion of "obj.Proxy.__class__" shown below, which would result in "ArachNURBS.ControlGrid44_4", but i can't figure out how to access this string (also a bit convoluted)

i have considered adding an attribute for the type to the objects themselves, but it will lead to lots of additional sorting and exceptions

does anyone have a simple solution to identify a python feature type?

Thanks!

Code: Select all

>>> obj = App.getDocument("Ellipsoid_Cap_04").getObject("ControlGrid44_4001")
>>> obj.FullName
'Ellipsoid_Cap_04#ControlGrid44_4001'
>>> obj.Name
'ControlGrid44_4001'
>>> obj.TypeId
'Part::FeaturePython'
>>> obj.Label
'ControlGrid44_4001test'
>>> obj.Proxy
<ArachNURBS.ControlGrid44_4 object at 0x7f7ca49a3550>
>>> obj.Proxy.__class__
<class 'ArachNURBS.ControlGrid44_4'>
vocx
Posts: 2718
Joined: Thu Oct 18, 2018 9:18 pm

Re: how to identify my Part::FeaturePython objects

Post by vocx » Sun Dec 29, 2019 1:51 am

emills2 wrote:
Sun Dec 29, 2019 1:14 am
...

does anyone have a simple solution to identify a python feature type?
The way the Draft and Arch workbenches do it, is to define a Type attribute for the Proxy.

Code: Select all

class _DraftObject:
    """The base class for Draft objects"""
    def __init__(self, obj, tp="Unknown"):
        if obj:
            obj.Proxy = self
        self.Type = tp
Then you can query your object.

Code: Select all

obj = App.ActiveDocument.addObject("Part::FeaturePython", "Something")

Draft._DraftObject(obj, "MyType")

print(obj.Proxy.Type)
As you found out, TypeId will give you only the parent C++ class.
To support the documentation effort, and code development, your donation is appreciated: paypal.
emills2
Posts: 593
Joined: Tue Apr 28, 2015 11:23 pm

Re: how to identify my Part::FeaturePython objects

Post by emills2 » Sun Dec 29, 2019 3:14 am

vocx wrote:
Sun Dec 29, 2019 1:51 am
The way the Draft and Arch workbenches do it, is to define a Type attribute for the Proxy.
that's interesting, is there a specific reason to add it to the proxy as opposed to the python feature definition?
vocx
Posts: 2718
Joined: Thu Oct 18, 2018 9:18 pm

Re: how to identify my Part::FeaturePython objects

Post by vocx » Sun Dec 29, 2019 3:30 am

emills2 wrote:
Sun Dec 29, 2019 3:14 am
that's interesting, is there a specific reason to add it to the proxy as opposed to the python feature definition?
I don't know for certain. I guess you could add it as a static, read-only property? Is that what you mean?

Maybe adding it to the Proxy is more efficient as you don't have to create a full property, just a basic Python attribute.

Maybe you can ask the Draft and Arch developer himself.

Draft and Arch objects TypeId
yorik wrote:
Mon Aug 26, 2019 2:57 pm
...

The idea of having a Type attribute inside the Proxy object was a dirty hack at first, but it has been more and more used all over FreeCAD (in FEM, Path, etc..) so it has now more or less become a norm now... Be careful of the dirty hacks you do, they might become the norm one day :D
To support the documentation effort, and code development, your donation is appreciated: paypal.
emills2
Posts: 593
Joined: Tue Apr 28, 2015 11:23 pm

Re: how to identify my Part::FeaturePython objects

Post by emills2 » Sun Dec 29, 2019 3:39 am

vocx wrote:
Sun Dec 29, 2019 3:30 am
...
yorik wrote:
Mon Aug 26, 2019 2:57 pm
... Be careful of the dirty hacks you do, they might become the norm one day :D
that's what i'm trying to look out for right now :) because it's going to underly my selection processing.

it's so frustrating to see

Code: Select all

>>> obj.Proxy.__class__
<class 'ArachNURBS.ControlGrid44_4'>
and not being able to extract the 'ArachNURBS.ControlGrid44_4' part as a string
User avatar
wandererfan
Posts: 3459
Joined: Tue Nov 06, 2012 5:42 pm

Re: how to identify my Part::FeaturePython objects

Post by wandererfan » Sun Dec 29, 2019 3:07 pm

emills2 wrote:
Sun Dec 29, 2019 3:39 am
and not being able to extract the 'ArachNURBS.ControlGrid44_4' part as a string
It is a fixed format, so pretty easy to extract the interesting bit by slicing.

Code: Select all

pClass = str(myObj.Proxy.__class__)[8:-2]
print("class: {}".format(pClass))
mlampert
Posts: 1458
Joined: Fri Sep 16, 2016 9:28 pm

Re: how to identify my Part::FeaturePython objects

Post by mlampert » Sun Dec 29, 2019 8:01 pm

emills2 wrote:
Sun Dec 29, 2019 3:39 am
it's so frustrating to see

Code: Select all

>>> obj.Proxy.__class__
<class 'ArachNURBS.ControlGrid44_4'>
and not being able to extract the 'ArachNURBS.ControlGrid44_4' part as a string
Don't know if you use the same proxy class for different types - but if you already have the proxy, can't you use

Code: Select all

isinstance(obj, ArchNURBS.ControlGrid)
... assuming that is your class name. Also, I recommend to wrap it into a function so there's only a single place to change if you ever change your mind ...
emills2
Posts: 593
Joined: Tue Apr 28, 2015 11:23 pm

Re: how to identify my Part::FeaturePython objects

Post by emills2 » Sun Dec 29, 2019 11:51 pm

wandererfan wrote:
Sun Dec 29, 2019 3:07 pm
It is a fixed format, so pretty easy to extract the interesting bit by slicing.
CODE: SELECT ALL

pClass = str(myObj.Proxy.__class__)[8:-2]
print("class: {}".format(pClass))
this is decent option, similar to parsing the object name
mlampert wrote:
Sun Dec 29, 2019 8:01 pm
Don't know if you use the same proxy class for different types - but if you already have the proxy, can't you use
CODE: SELECT ALL

isinstance(obj, ArchNURBS.ControlGrid)
that feels more direct, since i'm looking for a boolean answer in the end. turns out you have to target obj.Proxy, not just obj to get it to work.

Code: Select all

>>> Gui.Selection.setPreselection(App.getDocument('Unnamed').getObject('ControlPoly4_segment'),'',tp=2)
>>> obj = App.getDocument("Unnamed").getObject("ControlPoly4_segment")
>>> myclass = obj.Proxy.__class__
>>> myclass
<class 'ArachNURBS.ControlPoly4_segment'>
>>> isinstance(obj, ArachNURBS.ControlPoly4_segment)
False
>>> isinstance(obj.Proxy, ArachNURBS.ControlPoly4_segment)
True
>>> 
i really like this last one: isinstance(obj.Proxy, ArachNURBS.ControlPoly4_segment). i think this will be nicely readable.

Thanks everyone
vocx
Posts: 2718
Joined: Thu Oct 18, 2018 9:18 pm

Re: how to identify my Part::FeaturePython objects

Post by vocx » Mon Dec 30, 2019 12:26 am

emills2 wrote:
Sun Dec 29, 2019 11:51 pm
...
i really like this last one: isinstance(obj.Proxy, ArachNURBS.ControlPoly4_segment). i think this will be nicely readable.
What's wrong with using a Type attribute like Draft? Using the class name means that if you change the class you may need to change your test, but if you use a Type attribute, the implementation is a bit hidden, which is what Draft does.

Draft uses the command Draft.getType() precisely to get the type of the Proxy if it exists, or the C++ type in other cases.

https://github.com/FreeCAD/FreeCAD/blob ... #L202-L230

Code: Select all

def getType(obj):
    """getType(object): returns the Draft type of the given object"""
    import Part
    if not obj:
        return None
    if isinstance(obj,Part.Shape):
        return "Shape"
    if "Proxy" in obj.PropertiesList:
        if hasattr(obj.Proxy,"Type"):
            return obj.Proxy.Type
    if obj.isDerivedFrom("Sketcher::SketchObject"):
        return "Sketch"
    if (obj.TypeId == "Part::Line"):
        return "Part::Line"
    if (obj.TypeId == "Part::Offset2D"):
        return "Offset2D"
    if obj.isDerivedFrom("Part::Feature"):
        return "Part"
    if (obj.TypeId == "App::Annotation"):
        return "Annotation"
    if obj.isDerivedFrom("Mesh::Feature"):
        return "Mesh"
    if obj.isDerivedFrom("Points::Feature"):
        return "Points"
    if (obj.TypeId == "App::DocumentObjectGroup"):
        return "Group"
    if (obj.TypeId == "App::Part"):
        return "App::Part"
    return "Unknown"
Then you can use it like this

Code: Select all

if emills2.get_type(obj) == "Nurbs_control_poly4_segment":
    print("Correct type")
To support the documentation effort, and code development, your donation is appreciated: paypal.
emills2
Posts: 593
Joined: Tue Apr 28, 2015 11:23 pm

Re: how to identify my Part::FeaturePython objects

Post by emills2 » Mon Dec 30, 2019 5:01 am

vocx wrote:
Mon Dec 30, 2019 12:26 am
What's wrong with...
nothing wrong at all, and i may use it later. Right now isInstance() wins by a hair since it will perform the limited job i need with 0 changes to the class definition and object creation method. i could even implement the other method in parallel.
Post Reply

Who is online

Users browsing this forum: No registered users and 9 guests