View Issue Details

IDProjectCategoryView StatusLast Update
0001268FreeCADBugpublic2016-11-07 21:50
Reporterpkoning Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version0.13 
Summary0001268: FreeCAD python objects behave in many unPythonic ways
DescriptionI'm not sure whether to call this a feature request or a bug. For one thing, it's not a single issue, it's widespread.
The Python machinery of FreeCAD in many ways does things that are very surprising by Python conventions. While it's possible to work around this, it makes the code look very strange and makes for a lot more work. The general feel is of a C based API expressed in Python syntax.
A couple of examples:
1. "Duck typing" is not used. Attributes that expect integers complain if the value supplied is float (or the other way around, I forgot). The Python way would be to accept anything that acts like a number. (For example, Base.Vector().z=1 fails but Base.Vector().z=1.0 is accepted.)
2. Functions require lists instead of accepting any iterable.
3. Attributes have list type but don't act like lists: attempting to change a list member has no effect. The only way to modify the attribute is to get the whole list, modify that, and set it back into the attribute.
4. Subclassing is a pain. Each object in the 3d design corresponds to 3 objects in Python (the feature object, the view object, and the shape object of the feature). This seems to explain the existence of all the "makeXyz" functions. Subclassing in such a setting is hard. I tried to subclass Arch.Floor and ended up having to make a copy of Arch.makeFloor. It would seem to make a lot more sense for each feature to be just one class, with the view and shape and feature aspects provided by multiple inheritance. Then I could just subclass the feature, with new behavior provided by overrides to __init__ and/or other methods or new methods.
TagsNo tags attached.
FreeCAD Information

Activities

yorik

2013-10-07 17:10

administrator   ~0003720

About point 5, it is a very fundamental design decision of freecad to have those objects separated into these different components, and the advantages outweigh the inconveniences by far.

Something could probably be done for most of the other points, but your bug report is too generic and unprecise. If you are interested in putting more effort in this and help to get things better, I suggest you open a separate bug report for each specific problem you encounter.

wmayer

2013-10-08 07:25

administrator   ~0003721

1.) This is a limitation (or bug) in the PyCXX library we use.
2.) A concrete example for this?
3.) I guess that was a flaw due to lack of knowledge how to make a more Pythonic interface at that time. However, just changing the API here is even worse because this breaks a lot of scripts out there. Maybe this can be fixed once doing the port to Python3 which might be a major change.
4.) Indeed there are a lot of Python classes involved. The branch https://sourceforge.net/p/free-cad/code/ci/wmayer/featurepython/~/tree/ reduces the number of these Python classes. But as Yorik said you always need at least two Python classes -- one for the data stuff and one for the gui stuff.

wmayer

2013-10-08 08:54

administrator   ~0003722

git show 1e86035 fixes 1.)

pkoning

2013-10-08 15:25

reporter   ~0003723

Thanks!

I think I can see why two objects (structure vs. view) are good to have, but 3 is a puzzle.

An example of item 2: Part.makePolygon requires the first argument to be a list, it rejects a tuple as a type error.

On item 3: I don't think this requires breaking scripts. I'm not suggesting anything that is currently done should be made invalid, or should have a different meaning. The request is to make things that currently don't work start to work. For example, in ArchWindow, there is a property WIndowParts which is a list of strings. I tried to change one of those (as in "win.WindowParts[3] = "120"). That doesn't work. I end up having to do this:
  t = win.WindowParts
  t[3] = "120"
  win.WindowParts = t
which is something that no other Python module requires me to do.

wmayer

2013-10-09 07:06

administrator   ~0003724

> On item 3:
And that is exactly the problem. It's technically not possible to use a Python list and changing that outside of the scope of the FreeCAD object because this object won't be notified of the change. That's why an assignment is done to get this notification.
So, a solution is to use a tuple instead of a list because tuples are always immutable. This however changes the API and will be even less convenient but also less confusing.

pkoning

2013-10-09 13:06

reporter   ~0003725

Another option for item 3: use a subclass of list that adds notification. When assigning to the property, create an instance of that class from the supplied value. Then when assignment to an element is done, or append or extend is called (for example), the list subclass handles that.

wmayer

2013-10-09 14:36

administrator   ~0003726

Sure but I don't know how much work and how complicated that would be since all methods that modify the list must be re-implemented.

wmayer

2013-10-11 10:06

administrator   ~0003727

Issue 2. is solved now.

pkoning

2013-10-11 13:39

reporter   ~0003732

I just attached "notifylist.py" that shows a solution for item 3 (in Python -- but the equivalent can of course also be done in C if desired). The fact that Python allows "built in" types to be subclassed makes this easy.

yorik

2013-11-04 13:31

administrator  

notifylist.py (Attachment missing)

Jriegel

2013-11-06 19:53

administrator   ~0003862

Although 3. could maybe solved by a subscriber list, it would be confusing too. In that case lots of python object can float in the interpreter which change the document (and trigger the undo/redo framework and lots of stuff in gui). That would be very opaque. So working on copies and just assign the result is IMO the better solution!

shoogen

2013-11-07 14:57

developer   ~0003867

then we can return a tuple instead of list, to indicate that there have to be an assignment in end to change the c++ data structure.

Issue History

Date Modified Username Field Change
2013-10-07 14:15 pkoning New Issue
2013-10-07 17:10 yorik Note Added: 0003720
2013-10-08 07:25 wmayer Note Added: 0003721
2013-10-08 08:54 wmayer Note Added: 0003722
2013-10-08 15:25 pkoning Note Added: 0003723
2013-10-09 07:06 wmayer Note Added: 0003724
2013-10-09 13:06 pkoning Note Added: 0003725
2013-10-09 14:36 wmayer Note Added: 0003726
2013-10-11 10:06 wmayer Note Added: 0003727
2013-10-11 13:37 pkoning File Added: notifylist.py
2013-10-11 13:39 pkoning Note Added: 0003732
2013-11-04 13:31 yorik File Deleted: notifylist.py
2013-11-04 13:31 yorik File Added: notifylist.py
2013-11-06 19:53 Jriegel Note Added: 0003862
2013-11-07 14:57 shoogen Note Added: 0003867
2016-11-07 21:50 wmayer Status new => closed
2016-11-07 21:50 wmayer Resolution open => fixed