Hi, Frank:

I am not sure, but I think you could implement your utility function using a
python closure. This would allow the original object to remain in scope
until the nested function has completed. so for example:

To do closures in python, you have to use lamda, which creates a new
function having access to the outer scope, even after the function returns.
So

def MakeEdge(p1, p2):
    gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)]
    mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2)
    return mkedge.Shape()

Becomes:

def MakeEdge(p1,p2):
    gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)]
    mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2)
      return lambda e: mkedge.Shape();

now you can do
me = MakeEdge(p1,p2);

me.Shape() //return the generated shape
me.Shape() //return the generated shap again. It will be the same object
because the underlying brepbuilder is still in a closure

Now if you kill me, the closure will be discarded.

Dont know if this helps any or not.

On Tue, Mar 16, 2010 at 7:53 PM, Frank Conradie <fr...@qfin.net> wrote:

>  Hi Thomas
>
> After much investigation today, I have now added a flag to GarbageCollecter
> to disable it for our use, as it really does not work as intended for
> relatively complex code (I now manually track which objects I create and
> need to call _kill_pointed for). There are two main issues that we run into
> with the current GarbageCollector:
>
> 1. As already discussed, classes like the BRepPrimAPI and BRepAlgoAPI have
> an internal "myShape" data member that gets destroyed when the parent
> object's _kill_pointed method is called, causing all kinds of issues. As an
> example, it makes utility functions like the one below unusable, as the
> local BRepPrimAPI object goes out of scope and is thus collected by
> GarbageCollector for purging, even though the caller of the function may
> want to use the resulting shape for some time to come, after the parent is
> "purged":
>
> def MakeEdge(p1, p2):
>     gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)]
>     mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2)
>     return mkedge.Shape()
>
> 2. Every time a C++ OCC object is retrieved from Python in any way, a brand
> new SWIG wrapper object is instantiated for it, very easily/quickly leading
> to multiple wrapper objects on the Python side for the same underlying C++
> object (I see this especially when using OCC shape containers repeatedly).
> When any one of these wrapper objects goes out of scope and is collected and
> purged, the underlying C++ object is destroyed (via _kill_pointed), even
> though there may well be other Python wrapper objects still needing access
> to it.
>     I guess the ideal solution to this issue would be to keep a mapping of
> C++ object -> SWIG wrapper object on the C++ side, so that there is always a
> 1-to-1 correspondence between the two, but I'm not sure how plausible this
> really is from an implementation point-of-view. As an example of what I
> mean, consider this: every time you call "mkedge.Shape()" in my example
> above, you get a new/different Python object, wrapping the same underlying
> myShape instance, which is totally unexpected and unintuitive from a Python
> perspective. A "pure" Python programmer would expect to get the exact same
> Python object back every time, and not different wrapper objects with just
> an "artificial" identical hash value.
>
> I realize that this is a very difficult issue, and that as users of the
> PythonOCC wrapper library we will need to take responsibility for memory
> management issues, but I can see lots of confusion for Python programmers
> using the library and expecting "Python-like" behaviour out of the box.
>
> I wish I new more about the SWIG wrapper object instantiation process so
> that I could make more concrete suggestions, instead of just complaining
> ;-)  What is your gut-feeling about this Thomas - do you think these two
> issues can be addressed in the wrapper, or is the current way the only
> viable implementation? If you can give me a short description of the SWIG
> wrapper instantiation process, I may be able to delve into it myself.
>
> Thanks for your help with this thus far,
> Frank
>
>
>
>
> On 16/03/2010 9:04 AM, Thomas Paviot wrote:
>
> Hi Frank,
>
>  I also suggest you use the push_context() and pop_context() methods at
> the beginning and the end of your algorithm. garbage.push_context() creates
> a new collector. Objects collected will go to this new list. Then, at the
> end of your algorithm, just call .smart_purge() and then pop_context().
> Otherwise, when calling the smart_purge() method, you'll erase all other
> objects that might have been stored in the gc thus causing strange things.
>
>  def my_high_memory_consuming_algorithm():
>     GarbageCollector.garbage.push_context()
>
>      ... do whatever you want ...
>
>      GarbageCollector.garbage.smart_purge() #only the objects created
> since the call to push_context are erased. Use MMGT_OPT=0 to make sure
> freeing #memory.
>     GarbageCollector.pop_context()
>     return data
>
>  There's also a garbage.prevent_object(object) method, that will take care
> to not delete an object that it's important to keep reference.
>
>  These three functions are quite new (but validated with a unittest). I'm
> curious to have your feedback!
>
>  Regards,
>
>  Thomas
>
>  These two functions are quite new,
> 2010/3/16 Frank Conradie <fr...@qfin.net>
>
>> Hi Thomas
>>
>> Well, I'm glad it's not a bug then! I can think of a few ways to handle
>> this situation in my algorithm, so it should not be a problem. I'm just
>> wondering how many other classes behave in this "unexpected" way :O
>>
>> Cheers,
>> Frank
>>
>>
>> On 15/03/2010 10:26 PM, Thomas Paviot wrote:
>>
>> Hi Frank,
>>
>>  This behaviour does not come from SWIG but from OpenCASCADE itself. Let
>> me explain you in a few words what happens here.
>>
>>  The BRepPrimAPI_MakeBox class inherits from the BRepBuilderAPI_MakeShape
>> one. This class provides the Shape() method you can find in
>> BRepPrimAPI_Make* basic geometry constructors. If you have a look at  the
>> Shape() method in the file BRepBuilderAPI_MakeShape.cxx, you will read:
>>
>>  """
>>
>> //=======================================================================
>> //function : Shape
>> //purpose  :
>> //=======================================================================
>>
>>  const TopoDS_Shape&  BRepBuilderAPI_MakeShape::Shape() const
>> {
>>   if (!IsDone()) {
>>     // the following is const cast away
>>     ((BRepBuilderAPI_MakeShape*) (void*) this)->Build();
>>     Check();
>>   }
>>   return myShape;
>> }
>>  """
>>
>>  The Shape() method then returns a reference to the protected attribute
>> 'myShape' of the class BRepBuilderAPI_MakeBox. In other words, if you delete
>> the BRepPrimAPI_MakeBox instance, you loose the reference to the shape.
>>
>>  For instance:
>>
>>  >>> from OCC.BRepPrimAPI_MakeBox import *
>> >>> from OCC.TopoDS import *
>> >>> box = BRepPrimAPI_MakeBox(10,10,10)
>> >>> shp  = box.Shape()
>> >>> print shp.IsNull()
>> 0
>> >>> del box #object is garbage collected, not deleted yet
>> >>> print shp.IsNull()
>> 0
>> >>> GarbageCollector.garbage.smart_purge() # all objects are deleted,
>> loose the reference to myShape attribute
>> >>> print shp.IsNull()
>> 1
>>
>>  Then force objects deletion only if you're sure you don't need the
>> shapes anymore. I don't know what you're trying to do exactly, so it's
>> difficult to suggest any best practice.
>>
>>  Regards,
>>
>>  Thomas
>>
>> 2010/3/15 Frank Conradie <fr...@qfin.net>
>>
>>> Hi Thomas
>>>
>>> I am getting crash behaviour in the interim 0.5 PythonOCC release,
>>> related to the new GarbageCollector implementation. The code below
>>> crashes on my PC:
>>>
>>> ----------------------------------------
>>> from OCC.gp import *
>>> from OCC.BRepPrimAPI import *
>>> from OCC.BRepBuilderAPI import *
>>> from OCC.TopExp import *
>>> from OCC.TopoDS import *
>>>
>>> o = 0.0
>>> w = 0.1
>>> fp1 = (o,o,o)
>>> fp2 = (w,w,w)
>>>
>>> mkbox = BRepPrimAPI_MakeBox(gp_Pnt(fp1[0],fp1[1],fp1[2]),
>>> gp_Pnt(fp2[0],fp2[1],fp2[2]))
>>> s = mkbox.Shape()
>>> del mkbox
>>>
>>> print s.ShapeType()
>>> GarbageCollector.garbage.smart_purge()
>>> # The next line crashes my system
>>> print s.ShapeType()
>>> ----------------------------------------
>>>
>>> It is almost as if calling _kill_pointed for the mkbox causes shape "s"
>>> to become "corrupted" in some way. I dug through the SWIG code a bit,
>>> but cannot see anything obviously wrong, so I was hoping you could shed
>>> some light on the issue.
>>>
>>> By the way, I did get the SVN compiled myself as well, and get the same
>>> crash with my compiled lib as well as the one you made available on your
>>> website.
>>>
>>> Thanks,
>>> Frank
>>>
>>>
>>> _______________________________________________
>>> Pythonocc-users mailing list
>>> Pythonocc-users@gna.org
>>> https://mail.gna.org/listinfo/pythonocc-users
>>>
>>
>>
>> _______________________________________________
>> Pythonocc-users mailing 
>> listpythonocc-us...@gna.orghttps://mail.gna.org/listinfo/pythonocc-users
>>
>>
>> _______________________________________________
>> Pythonocc-users mailing list
>> Pythonocc-users@gna.org
>> https://mail.gna.org/listinfo/pythonocc-users
>>
>>
>
> _______________________________________________
> Pythonocc-users mailing 
> listpythonocc-us...@gna.orghttps://mail.gna.org/listinfo/pythonocc-users
>
>
> _______________________________________________
> Pythonocc-users mailing list
> Pythonocc-users@gna.org
> https://mail.gna.org/listinfo/pythonocc-users
>
>
_______________________________________________
Pythonocc-users mailing list
Pythonocc-users@gna.org
https://mail.gna.org/listinfo/pythonocc-users

Reply via email to