Why would you want to have a domain specific language (DSL) in a django app? Especially for use by the actual end-users of your website?
The initial motivation was for searching contacts in a contact database. Especially the group affiliations were a problem. The rules kept changing. And what to do, for instance, with contacts that are not in groups, compared to contacts that are in a group?
Some things are very hard to do in a GUI. How would you make a GUI in which you could represent a query/action like the following?:
rotate 90
if height > 600px
resize to height=600px
while face_dectected: f
blur f
Something like this is easier to do in a DSL. Such a DSL might not be the thing for most users. But power users could work with it and set up add-ons for the regular users.
A DSL needs three elements:
A lexer uses a vocubulary to turn a bunch of characters into a bunch of words.
A parser uses a grammar* to turn that bunch of words into structured information.
The backend is supposed to do something specific with the structure information. In the example we’ll use the django ORM (specifically, Q objects).
PLY is an implementation of lex and yacc for python. Lex and yacc are the standard lexer/parser in the unix world. Because of naming conventions and introspection, ply allows you to be very economic with your code.
(Matthieu showed example code. It did indeed look economic. A bit strange in places, but very readable once he explained it. Looks fun! “A bit strange” is mostly “regex as docstring”, btw. Look at his slides)
A string like modified > 1/4/2011 OR NOT state="VA"
would get turned into
Q objects. state="VA"
would be lexed/parsed into “field called ‘state’”,
“equals operator” and “string VA”. The result is Q(state__exact='VA')
,
which you can feed to YourModel.objects.filter()
.
PLY actually works really well (and reasonably easy) when combined with Django’s query language by using those Q objects. So as long as you want to query the ORM it will be possible to use a DSL.
A more functional approach with actions is harder. You could create lambda functions and execute them. (Reinout: sounds a bit dangerous?)
(Reinout: looked like fun! And python’s dynamic character shines here, too.)
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):