Jump to content
  • Advertisement
Sign in to follow this  
crivens

Converting tiny subset of English to Python - any suggestions how?

This topic is 3752 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to write a 'wizard' for users to make it easier for them generate Python logic, which in this app is basically a bunch of if statements to implement business logic. The users aren't developers and asking them to write Python won't go down well. One option that sprung to mind was to let them use a tiny subset of English to generate the business logic, and then write a tool to parse and convert it to Python. The business logic is contains filters (if statements) and modifiers (modifying data, obviously!). Here's a simple example: The English for the filter would be:
person.name is "fred" and person.age is 25 and person.address contains "canada"
The tool would convert this to Python:
if person.get_value("name") == "fred" and person.get_value("age") == 25 and person.get_status().find("canada") > -1:
The English for the modifier would be:
person.salary to 20000 and person.status to "hired"
Which would be converted to:
person.set_value("salary", 20000)
person.set_value("status", "hired")

Hopefully that makes sense. I started writing my tool to perform the filter conversion. I parse the string andI break it down into tokens for each possible English word, so: TOKEN_AND TOKEN_STRING TOKEN_VARIABLE (e.g. person) etc. I've also added logic to determine which tokens can precede or follow other tokens and that works nicely. But what's next? How do I take the list (stream I guess) of tokens and convert it into Python? Do I turn the stream into a tree, where, for example, TOKEN_AND is a branch, and TOKEN_STRING is a leaf? Then traverse the tree to generate the Python? I tried this, but I couldn't get it working. Any suggestions? Many thanks

Share this post


Link to post
Share on other sites
Advertisement
get_value? set_value?

If you'd just write idiomatic Python, your users could write statements directly in Python rather than an arbitrary "English subset". You can still validate on write or compute on read by using Python properties.


class Person(object):
def __init__(self, name, age, address):
self.__name = name
self.__age = age
self.__address = address.split('\n') # break on newlines, creating a list
# set other default properties here

def __set_name(self, value):
# perform validation of value here

self.__name = value

name = property((lambda self: self.__name), __set_name)

# other setters and property declarations here



Now your users can write:
person.name is 'fred' and person.age is 25 and 'canada' in person.address

...and it's actually Python code!

Share this post


Link to post
Share on other sites
The Person object is a C++ class wrapped using Boost Python, and data is accessed using set_value/get_value. Odd I know, but it's legacy and zero chance to change it. :)

Thanks - I'll try your suggestion out.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
The Python interface of an exposed class does not have to match the C++ interface.


Yeah that took me a while to realise, for some reason, and now I'm considering redefining __getattr__ and __setattr__.

Share this post


Link to post
Share on other sites
Quote:
Original post by Oluseyi
get_value? set_value?

If you'd just write idiomatic Python, your users could write statements directly in Python rather than an arbitrary "English subset". You can still validate on write or compute on read by using Python properties.

*** Source Snippet Removed ***

Now your users can write:
person.name is 'fred' and person.age is 25 and 'canada' in person.address

...and it's actually Python code!


I think this will work beautifully. I added functions for__getattr__ and __setattr__ to my base class (that Person derives from) that simply do this. I can't see anything that might be dangerous here.

CString __getattr__ (CEntity& entity, const CString& value)
{
return entity.GetValue(value);
}


Sweet!! My boss seems impressed and I think it might just help appease the non-technical users.

Share this post


Link to post
Share on other sites
That's weird. This never evaluates:

person.name is "fred"




But this does:

person.name == "fred"



It'll only correctly determine string equality when I use the equals operator (==). If I use 'is', the equality always fails. Any ideas?

It only fails when executing python script embedded in my app. It works fine if I run the same source from an IDE (PyScipter).

Share this post


Link to post
Share on other sites
Quote:
Original post by crivens
Any ideas?

The is operator evaluates reference equality. The == operator evaluates value equality. Since Python strings are immutable, multiple strings with the same literal value will all refer to the same object, and thus will yield both value and reference equality (even for computed values: 'fred' is 'fr' + 'ed' returns True).

When your python is embedded in your app, however, I suspect that the values in person are being set by the C++ side of things, which means it is not the same object (reference inequality) as the Python side, this is fails but == succeeds.

The only solution I can think of is to instrument your __getattr__ method to return a Python-equivalent string object when queried for name, so is will work, or to define an automatic conversion between CString and PyStringObject.

Share this post


Link to post
Share on other sites
Thanks! I read up on 'is' and came to the same conclusion. I change my __getattr__ function (this is C++) to return boost::python::str but it doesn't seem to correct the issue.

boost::python::str get_attr(CEntity& entity, const CString& name)
{
return boost::python::str(entity.GetValue(name));
}



And then later:

		.def("__getattr__", &get_attr)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!