getting a list of strings from a static method

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

getting a list of strings from a static method

Josh Stratton
I'm very new to boost python and trying to figure out how to properly
get a list of strings from a static method in my main namespace.  I'm
not sure if I need to extract the list from the object or if it's
already a list.

boost::python::object list = exec("Foo.extensions()",
_pyMainNamespace); // where Foo.extensions() is a static method
returning a list of strings

My end goal is to have a QList of QStrings, but if I can somehow get
them to a boost list of std::strings I can take it from there.
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Boost Python loss of values

Jay Riley
I'm having a really weird issue in boost python. I'm focusing on a particular property/method to simplify the example. Here's the situation:

In my program, I have a class called Attack. With the following layout (simplified for example)

    class Attack : public Action
    {
    public:
        virtual int CalculateDamage(const std::vector<BattleCharacter*>& users, BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, BattleField *field);
    protected:
        bool Hit;
    }

I exposed Attack to python, making it overridable, as follows:

    struct AttackWrapper : Game::Battles::Actions::Attack
    {
        int AttackWrapper::CalculateDamage(const std::vector<Game::Battles::BattleCharacter*>& users, Game::Battles::BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField *field)
        {
               return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));
        }
        int AttackWrapper::CalculateDamageDefault(const std::vector<Game::Battles::BattleCharacter*>& users, Game::Battles::BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField *field)
        {
            return this->Attack::CalculateDamage(users, target, Targets, field);
        }
    }

And the python exposing is done as follows:

    class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action> >("Attack")
        .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);


I initially thought everything was working fine, as I can override the `CalculateDamage` method within python and have it work correctly. However, When I want to use the normal `Attack->CalculateDamage`, the following happens:

I only call `CalculateDamage` when Hit is true, and I can confirm via break point when I hit this line, Hit is true:

    return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));

Now, because I haven't overriden `CalculateDamage` in Python for this attack instance, it ends up resolving to `AttackWrapper::CalculateDamageDefault`. But by the time I enter AttackWrapper::CalculateDamageDefault, Hit is no longer true. That is, when I break on this line:

    return this->Attack::CalculateDamage(users, target, Targets, field);

Hit is false. So somewhere between

    return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));

resolving to

    return this->Attack::CalculateDamage(users, target, Targets, field);

my property's value is lost. I have no idea what could be causing this. Has anyone encountered something like this before?

The attacks I'm using for testing are defined as follows:

class ScriptedAttack(Attack):
    def __init__(self, Type, ID, Name, Flags, Targs = ActionTargets.Any, AllowTargettingOverride = False, Power = 0, MPCost = 0, SPCost = 0, Accuracy = 0.9, CritChance = 0.1, DefineOwnUse = False, EleWeights = None, StatusEffectChances = None):
        if (EleWeights == None and StatusEffectChances == None):
            Attack.__init__(self, Type, ID, Name, Flags, Targs, AllowTargettingOVerride, Power, MPCost, SPCost, Accuracy, CritChance, DefineOwnUse)
        else:
            Elemap = ElementMap()
            if (EleWeights != None):
                for Element, Weight in EleWeights.iteritems():
                    Elemap[Element] = Weight
            SEChances = SEChanceMap()
            if (StatusEffectChances != None):
                for StatusEffect, Chance in StatusEffectChances.iteritems():
                    SEChances[StatusEffect] = Chance
            Attack.__init__(self, Type, ID, Name, Flags, Elemap, Targs, AllowTargettingOverride, Power, MPCost, SPCost, Accuracy, CritChance, DefineOwnUse, SEChances)
    def Clone(self):
        return copy.deepcopy(self)

Fire = ScriptedAttack(ActionType.MagicAction, PrimaryEngine.GetUID(), "Fire", AttackFlags.Projectile | AttackFlags.Elemental, ActionTargets.Any, True, 32, 14, 0, 1.0, 0.1, False, {Elements.Fire: 1.0})
Fira = ScriptedAttack(ActionType.MagicAction, PrimaryEngine.GetUID(), "Fira", AttackFlags.Projectile | AttackFlags.Elemental, ActionTargets.Any, True, 63, 35, 0, 1.0, 0.1, False, {Elements.Fire: 1.0})

ActLibrary.AddAttack(Fire)
ActLibrary.AddAttack(Fira)

ActLibrary.AddAttack takes in a boost::shared_ptr<Attack> and stores it into a hash table. I lookup the attack and use the instance stored there to do CalculateDamage.

It almost seems like the object is being copied, but I have no idea why that'd be so.

Any help would be appreciated.

Thanks

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: getting a list of strings from a static method

Jim Bosch-2
In reply to this post by Josh Stratton
On 08/24/2011 10:07 PM, Josh Stratton wrote:
> I'm very new to boost python and trying to figure out how to properly
> get a list of strings from a static method in my main namespace.  I'm
> not sure if I need to extract the list from the object or if it's
> already a list.
>
> boost::python::object list = exec("Foo.extensions()",
> _pyMainNamespace); // where Foo.extensions() is a static method
> returning a list of strings
>

Something like this:

namespace bp = boost::python;
bp::object pyList = bp::exec("Foo.extensions()", _pyMainNamespace);
std::vector<std::string> vec(bp::len(pyList));
for (std::size_t i = 0; i < vec.size(); ++i) {
    vec[i] = bp::extract<std::string>(pyList[i]);
}

> My end goal is to have a QList of QStrings, but if I can somehow get
> them to a boost list of std::strings I can take it from there.

I'll leave converting to Qt stuff up to you.  Note that you can also do
extract<char const *>(), which may be more efficient if you have really
large strings and don't want to copy them.

Good Luck!

Jim Bosch

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Boost Python loss of values

Jim Bosch-2
In reply to this post by Jay Riley
On 08/25/2011 04:17 AM, Jay Riley wrote:

>
> And the python exposing is done as follows:
>
> class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action>
>  >("Attack")
> .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);
>

This bit looks a little suspect, and I'm surprised that it compiles -
class_ should only take 4 arguments if one of them is boost::noncopyable.

I think you mean:

class_< Attack, boost::shared_ptr<AttackWrapper>, bases<Action> >
(...)

See

http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html

for details of the arguments to class_.

I don't have a good idea as to why this would cause the problem you're
seeing (maybe you're slicing your AttackWrapper instances into Attack
instances?) but I'd recommend fixing it first.

Good Luck!

Jim Bosch
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Boost Python loss of values

Jay Riley
Hi Jim,

Thanks for the suggestion, unfortunately it didn't work. It really feels like it's making a copy for some reason as once I return to the

  int AttackWrapper::CalculateDamage(const std::vector<Game::Battles::BattleCharacter*>& users, Game::Battles::BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField *field)
        {
               return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));
        }

function, the value are back to their expected value. Slicing wouldn't be a problem here would it, since Hit is a member of the base class anyways?

> Date: Thu, 25 Aug 2011 13:18:04 -0700

> From: [hidden email]
> To: [hidden email]
> CC: [hidden email]
> Subject: Re: [C++-sig] Boost Python loss of values
>
> On 08/25/2011 04:17 AM, Jay Riley wrote:
>
> >
> > And the python exposing is done as follows:
> >
> > class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action>
> > >("Attack")
> > .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);
> >
>
> This bit looks a little suspect, and I'm surprised that it compiles -
> class_ should only take 4 arguments if one of them is boost::noncopyable.
>
> I think you mean:
>
> class_< Attack, boost::shared_ptr<AttackWrapper>, bases<Action> >
> (...)
>
> See
>
> http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html
>
> for details of the arguments to class_.
>
> I don't have a good idea as to why this would cause the problem you're
> seeing (maybe you're slicing your AttackWrapper instances into Attack
> instances?) but I'd recommend fixing it first.
>
> Good Luck!
>
> Jim Bosch

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Boost Python loss of values

Jim Bosch-2
On 08/26/2011 08:27 AM, Jay Riley wrote:

> Hi Jim,
>
> Thanks for the suggestion, unfortunately it didn't work. It really feels
> like it's making a copy for some reason as once I return to the
>
> int AttackWrapper::CalculateDamage(const
> std::vector<Game::Battles::BattleCharacter*>& users,
> Game::Battles::BattleCharacter* target, const
> std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField
> *field)
> {
> return call_method<int>(self, "CalculateDamage", users, ptr(target),
> targets, ptr(field));
> }
>
> function, the value are back to their expected value. Slicing wouldn't
> be a problem here would it, since Hit is a member of the base class anyways?
>

Yes, that's right.  What exactly is "self", above?  I assume it's a data
member of AttackWrapper of type PyObject *, which shouldn't produce a
copy, but if it's something else, well, that could be a factor.

Jim



>  > Date: Thu, 25 Aug 2011 13:18:04 -0700
>  > From: [hidden email]
>  > To: [hidden email]
>  > CC: [hidden email]
>  > Subject: Re: [C++-sig] Boost Python loss of values
>  >
>  > On 08/25/2011 04:17 AM, Jay Riley wrote:
>  >
>  > >
>  > > And the python exposing is done as follows:
>  > >
>  > > class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action>
>  > > >("Attack")
>  > > .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);
>  > >
>  >
>  > This bit looks a little suspect, and I'm surprised that it compiles -
>  > class_ should only take 4 arguments if one of them is boost::noncopyable.
>  >
>  > I think you mean:
>  >
>  > class_< Attack, boost::shared_ptr<AttackWrapper>, bases<Action> >
>  > (...)
>  >
>  > See
>  >
>  > http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html
>  >
>  > for details of the arguments to class_.
>  >
>  > I don't have a good idea as to why this would cause the problem you're
>  > seeing (maybe you're slicing your AttackWrapper instances into Attack
>  > instances?) but I'd recommend fixing it first.
>  >
>  > Good Luck!
>  >
>  > Jim Bosch
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> [hidden email]
> http://mail.python.org/mailman/listinfo/cplusplus-sig

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Boost Python loss of values

Jay Riley
Self is indeed a PyObject*

this is a bit confusing

> Date: Fri, 26 Aug 2011 13:00:11 -0700

> From: [hidden email]
> To: [hidden email]
> Subject: Re: [C++-sig] Boost Python loss of values
>
> On 08/26/2011 08:27 AM, Jay Riley wrote:
> > Hi Jim,
> >
> > Thanks for the suggestion, unfortunately it didn't work. It really feels
> > like it's making a copy for some reason as once I return to the
> >
> > int AttackWrapper::CalculateDamage(const
> > std::vector<Game::Battles::BattleCharacter*>& users,
> > Game::Battles::BattleCharacter* target, const
> > std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField
> > *field)
> > {
> > return call_method<int>(self, "CalculateDamage", users, ptr(target),
> > targets, ptr(field));
> > }
> >
> > function, the value are back to their expected value. Slicing wouldn't
> > be a problem here would it, since Hit is a member of the base class anyways?
> >
>
> Yes, that's right. What exactly is "self", above? I assume it's a data
> member of AttackWrapper of type PyObject *, which shouldn't produce a
> copy, but if it's something else, well, that could be a factor.
>
> Jim
>
>
>
> > > Date: Thu, 25 Aug 2011 13:18:04 -0700
> > > From: [hidden email]
> > > To: [hidden email]
> > > CC: [hidden email]
> > > Subject: Re: [C++-sig] Boost Python loss of values
> > >
> > > On 08/25/2011 04:17 AM, Jay Riley wrote:
> > >
> > > >
> > > > And the python exposing is done as follows:
> > > >
> > > > class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action>
> > > > >("Attack")
> > > > .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);
> > > >
> > >
> > > This bit looks a little suspect, and I'm surprised that it compiles -
> > > class_ should only take 4 arguments if one of them is boost::noncopyable.
> > >
> > > I think you mean:
> > >
> > > class_< Attack, boost::shared_ptr<AttackWrapper>, bases<Action> >
> > > (...)
> > >
> > > See
> > >
> > > http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html
> > >
> > > for details of the arguments to class_.
> > >
> > > I don't have a good idea as to why this would cause the problem you're
> > > seeing (maybe you're slicing your AttackWrapper instances into Attack
> > > instances?) but I'd recommend fixing it first.
> > >
> > > Good Luck!
> > >
> > > Jim Bosch
> >
> >
> > _______________________________________________
> > Cplusplus-sig mailing list
> > [hidden email]
> > http://mail.python.org/mailman/listinfo/cplusplus-sig
>
> _______________________________________________
> Cplusplus-sig mailing list
> [hidden email]
> http://mail.python.org/mailman/listinfo/cplusplus-sig

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: Boost Python loss of values

Jim Bosch-2
On 08/30/2011 07:58 AM, Jay Riley wrote:
> Self is indeed a PyObject*
>
> this is a bit confusing
>

I'm afraid my next piece of advice is to simplify this like crazy, and
see if you can replicate the problem in a very minimal example.  If you
can get it small enough, I can take a look at the whole thing and see if
I can figure out what's going on.

Jim



>  > Date: Fri, 26 Aug 2011 13:00:11 -0700
>  > From: [hidden email]
>  > To: [hidden email]
>  > Subject: Re: [C++-sig] Boost Python loss of values
>  >
>  > On 08/26/2011 08:27 AM, Jay Riley wrote:
>  > > Hi Jim,
>  > >
>  > > Thanks for the suggestion, unfortunately it didn't work. It really
> feels
>  > > like it's making a copy for some reason as once I return to the
>  > >
>  > > int AttackWrapper::CalculateDamage(const
>  > > std::vector<Game::Battles::BattleCharacter*>& users,
>  > > Game::Battles::BattleCharacter* target, const
>  > > std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField
>  > > *field)
>  > > {
>  > > return call_method<int>(self, "CalculateDamage", users, ptr(target),
>  > > targets, ptr(field));
>  > > }
>  > >
>  > > function, the value are back to their expected value. Slicing wouldn't
>  > > be a problem here would it, since Hit is a member of the base class
> anyways?
>  > >
>  >
>  > Yes, that's right. What exactly is "self", above? I assume it's a data
>  > member of AttackWrapper of type PyObject *, which shouldn't produce a
>  > copy, but if it's something else, well, that could be a factor.
>  >
>  > Jim
>  >
>  >
>  >
>  > > > Date: Thu, 25 Aug 2011 13:18:04 -0700
>  > > > From: [hidden email]
>  > > > To: [hidden email]
>  > > > CC: [hidden email]
>  > > > Subject: Re: [C++-sig] Boost Python loss of values
>  > > >
>  > > > On 08/25/2011 04:17 AM, Jay Riley wrote:
>  > > >
>  > > > >
>  > > > > And the python exposing is done as follows:
>  > > > >
>  > > > > class_<Attack, AttackWrapper, boost::shared_ptr<Attack>,
> bases<Action>
>  > > > > >("Attack")
>  > > > > .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);
>  > > > >
>  > > >
>  > > > This bit looks a little suspect, and I'm surprised that it compiles -
>  > > > class_ should only take 4 arguments if one of them is
> boost::noncopyable.
>  > > >
>  > > > I think you mean:
>  > > >
>  > > > class_< Attack, boost::shared_ptr<AttackWrapper>, bases<Action> >
>  > > > (...)
>  > > >
>  > > > See
>  > > >
>  > > > http://www.boost.org/doc/libs/1_47_0/libs/python/doc/v2/class.html
>  > > >
>  > > > for details of the arguments to class_.
>  > > >
>  > > > I don't have a good idea as to why this would cause the problem
> you're
>  > > > seeing (maybe you're slicing your AttackWrapper instances into Attack
>  > > > instances?) but I'd recommend fixing it first.
>  > > >
>  > > > Good Luck!
>  > > >
>  > > > Jim Bosch
>  > >
>  > >
>  > > _______________________________________________
>  > > Cplusplus-sig mailing list
>  > > [hidden email]
>  > > http://mail.python.org/mailman/listinfo/cplusplus-sig
>  >
>  > _______________________________________________
>  > Cplusplus-sig mailing list
>  > [hidden email]
>  > http://mail.python.org/mailman/listinfo/cplusplus-sig
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> [hidden email]
> http://mail.python.org/mailman/listinfo/cplusplus-sig

_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig