SlideShare a Scribd company logo
1 of 48
Download to read offline
Domain Specific Languages in
         Python




    Siddharta Govindaraj
siddharta@silverstripesoftware.com
What are DSLs?

Specialized mini-languages for specific problem
domains that make it easier to work in that
domain
Example: SQL

SQL is a mini language specialized to retrieve data
from a relational database
Example: Regular Expressions

Regular Expressions are mini languages
specialized to express string patterns to match
Life Without Regular Expressions
def is_ip_address(ip_address):
    components = ip_address_string.split(".")
    if len(components) != 4: return False
    try:
        int_components = [int(component) for component in
components]
    except ValueError:
           return False
    for component in int_components:
           if component < 0 or component > 255:
               return False
    return True
Life With Regular Expressions
def is_ip(ip_address_string):
    match = re.match(r"^(d{1,3}).(d{1,3}).(d{1,3}).
(d{1,3})$", ip_address_string)
    if not match: return False
    for component in match.groups():
        if int(component) < 0 or int(component) > 255:
return False
    return True
The DSL that simplifies our life


 ^(d{1,3}).(d{1,3}).(d{1,3}).(d{1,3})$
Why DSL - Answered

When working in a particular domain, write your
code in a syntax that fits the domain.

             When working with patterns, use RegEx
              When working with RDBMS, use SQL
       When working in your domain – create your own DSL
The two types of DSLs

External DSL – The code is written in an external
file or as a string, which is read and parsed by the
application
The two types of DSLs

Internal DSL – Use features of the language (like
metaclasses) to enable people to write code in
python that resembles the domain syntax
Creating Forms – No DSL
<form>
<label>Name:</label><input type=”text” name=”name”/>
<label>Email:</label><input type=”text” name=”email”/>
<label>Password:</label><input type=”password”
name=”name”/>
</form>
Creating Forms – No DSL

– Requires HTML knowledge to maintain
– Therefore it is not possible for the end user to
change the structure of the form by themselves
Creating Forms – External DSL
UserForm
name->CharField label:Username
email->EmailField label:Email Address
password->PasswordField




This text file is parsed and rendered by the app
Creating Forms – External DSL

+ Easy to understand form structure
+ Can be easily edited by end users
– Requires you to read and parse the file
Creating Forms – Internal DSL
class UserForm(forms.Form):
    username = forms.RegexField(regex=r'^w+$',
          max_length=30)
    email = forms.EmailField(maxlength=75)
    password =
          forms.CharField(widget=forms.PasswordInput())




Django uses metaclass magic to convert this
syntax to an easily manipulated python class
Creating Forms – Internal DSL

+ Easy to understand form structure
+ Easy to work with the form as it is regular python
+ No need to read and parse the file
– Cannot be used by non-programmers
– Can sometimes be complicated to implement
– Behind the scenes magic → debugging hell
Creating an External DSL
UserForm
name:CharField -> label:Username size:25
email:EmailField -> size:32
password:PasswordField




Lets write code to parse and render this form
Options for Parsing

Using string functions → You have to be crazy
Using regular expressions →
Some people, when confronted with a problem, think "I know, I'll use
regular expressions." Now they have two problems. - Jamie Zawinski


Writing a parser →         ✓   (we will use PyParsing)
Step 1: Get PyParsing
   pip install pyparsing
Step 2: Design the Grammar
form ::= form_name newline field+
field ::= field_name colon field_type [arrow property+]
property ::= key colon value
form_name ::= word
field_name ::= word
field_type ::= CharField | EmailField | PasswordField
key ::= word
value ::= alphanumeric+
word ::= alpha+
newline ::= n
colon ::= :
arrow ::= ->
Quick Note

Backus-Naur Form (BNF) is a syntax for
specifying grammers
Step 3: Implement the Grammar
newline = "n"
colon = ":"
arrow = "->"
word = Word(alphas)
key = word
value = Word(alphanums)
field_type = oneOf("CharField EmailField PasswordField")
field_name = word
form_name = word
field_property = key + colon + value
field = field_name + colon + field_type +
     Optional(arrow + OneOrMore(field_property)) + newline
form = form_name + newline + OneOrMore(field)
Quick Note

PyParsing itself implements a neat little internal
DSL for you to describe the parser grammer


Notice how the PyParsing code almost perfectly
reflects the BNF grammer
Output
> print form.parseString(input_form)


['UserForm', 'n', 'name', ':', 'CharField', '->',
'label', ':', 'Username', 'size', ':', '25', 'n',
'email', ':', 'EmailField', '->', 'size', ':', '25', 'n',
'password', ':', 'PasswordField', 'n']




PyParsing has neatly parsed our form input into
tokens. Thats nice, but we can do more.
Step 4: Suppressing Noise Tokens
newline = Suppress("n")
colon = Suppress(":")
arrow = Suppress("->")
Output
> print form.parseString(input_form)


['UserForm', 'name', 'CharField', 'label', 'Username',
'size', '25', 'email', 'EmailField', 'size', '25',
'password', 'PasswordField']




All the noise tokens are now removed from the
parsed output
Step 5: Grouping Tokens
field_property = Group(key + colon + value)
field = Group(field_name + colon + field_type +
Group(Optional(arrow + OneOrMore(field_property))) +
newline)
Output
> print form.parseString(input_form)


['UserForm',
  ['name', 'CharField',
    [['label', 'Username'], ['size', '25']]],
  ['email', 'EmailField',
    [['size', '25']]],
  ['password', 'PasswordField',[]]]

Related tokens are now grouped together in a list
Step 6: Give Names to Tokens
form_name = word.setResultsName("form_name")
field = Group(field_name + colon + field_type +
  Group(Optional(arrow + OneOrMore(field_property))) +
  newline).setResultsName("form_field")
Output
> parsed_form = form.parseString(input_form)
> print parsed_form.form_name


UserForm


> print parsed_form.fields[1].field_type


EmailField




Now we can refer to parsed tokens by name
Step 7: Convert Properties to Dict
def convert_prop_to_dict(tokens):
    prop_dict = {}
    for token in tokens:
        prop_dict[token.property_key] =
                                    token.property_value
    return prop_dict


field = Group(field_name + colon + field_type +
          Optional(arrow + OneOrMore(field_property))
             .setParseAction(convert_prop_to_dict) +
          newline).setResultsName("form_field")
Output
> print form.parseString(input_form)


['UserForm',
    ['name', 'CharField',
      {'size': '25', 'label': 'Username'}],
    ['email', 'EmailField',
      {'size': '32'}],
    ['password', 'PasswordField', {}]
]


Sweet! The field properties are parsed into a dict
Step 7: Generate HTML Output

We need to walk through the parsed form and
generate a html string out of it
def get_field_html(field):

   properties = field[2]

   label = properties["label"] if "label" in properties else field.field_name

   label_html = "<label>" + label + "</label>"

   attributes = {"name":field.field_name}

   attributes.update(properties)

   if field.field_type == "CharField" or field.field_type == "EmailField":

       attributes["type"] = "text"

   else:

       attributes["type"] = "password"

   if "label" in attributes:

       del attributes["label"]

   attributes_html = " ".join([name+"='"+value+"'" for name,value in attributes.items()])

   field_html = "<input " + attributes_html + "/>"

   return label_html + field_html + "<br/>"



def render(form):

   fields_html = "".join([get_field_html(field) for field in form.fields])

   return "<form id='" + form.form_name.lower() +"'>" + fields_html + "</form>"
Output
> print render(form.parseString(input_form))


<form id='userform'>
<label>Username</label>
<input type='text' name='name' size='25'/><br/>
<label>email</label>
<input type='text' name='email' size='32'/><br/>
<label>password</label>
<input type='password' name='password'/><br/>
</form>
It works, but....


                 Yuck!


The output rendering code is an UGLY MESS
Wish we could do this...
> print Form(CharField(name=”user”,size=”25”,label=”ID”),
             id=”myform”)


<form id='myform'>
<label>ID</label>
<input type='text' name='name' size='25'/><br/>
</form>




Neat, clean syntax that matches the output domain
well. But how do we create this kind of syntax?
Lets create an Internal DSL
class HtmlElement(object):

   default_attributes = {}

   tag = "unknown_tag"



   def __init__(self, *args, **kwargs):

       self.attributes = kwargs

       self.attributes.update(self.default_attributes)

       self.children = args



   def __str__(self):

       attribute_html = " ".join(["{}='{}'".format(name, value) for name,value in
                                                           self.attributes.items()])

       if not self.children:

            return "<{} {}/>".format(self.tag, attribute_html)

       else:

            children_html = "".join([str(child) for child in self.children])

            return "<{} {}>{}</{}>".format(self.tag, attribute_html, children_html,
self.tag)
> print HtmlElement(id=”test”)



<unknown_tag id='test'/>



> print HtmlElement(HtmlElement(name=”test”), id=”id”)



<unknown_tag id='id'><unknown_tag name='test'/></unknown_tag>
class Input(HtmlElement):

   tag = "input"



   def __init__(self, *args, **kwargs):

       HtmlElement.__init__(self, *args, **kwargs)

       self.label = self.attributes["label"] if "label" in self.attributes else

                                                             self.attributes["name"]

       if "label" in self.attributes:

           del self.attributes["label"]



   def __str__(self):

       label_html = "<label>{}</label>".format(self.label)

       return label_html + HtmlElement.__str__(self) + "<br/>"
> print InputElement(name=”username”)



<label>username</label><input name='username'/><br/>



> print InputElement(name=”username”, label=”User ID”)



<label>User ID</label><input name='username'/><br/>
class Form(HtmlElement):

   tag = "form"



class CharField(Input):

   default_attributes = {"type":"text"}



class EmailField(CharField):

   pass



class PasswordField(Input):

   default_attributes = {"type":"password"}
Now...
> print Form(CharField(name=”user”,size=”25”,label=”ID”),
             id=”myform”)


<form id='myform'>
<label>ID</label>
<input type='text' name='name' size='25'/><br/>
</form>




                            Nice!
Step 7 Revisited: Output HTML
def render(form):
    field_dict = {"CharField": CharField, "EmailField":
               EmailField, "PasswordField": PasswordField}
    fields = [field_dict[field.field_type]
          (name=field.field_name, **field[2]) for field in
                                              form.fields]
    return Form(*fields, id=form.form_name.lower())




Now our output code uses our Internal DSL!
INPUT
UserForm
name:CharField -> label:Username size:25
email:EmailField -> size:32
password:PasswordField
                          OUTPUT
<form id='userform'>
<label>Username</label>
<input type='text' name='name' size='25'/><br/>
<label>email</label>
<input type='text' name='email' size='32'/><br/>
<label>password</label>
<input type='password' name='password'/><br/>
</form>
Get the whole code

http://bit.ly/pyconindia_dsl
Summary

+ DSLs make your code easier to read
+ DSLs make your code easier to write
+ DSLs make it easy to for non-programmers to
maintain code
+ PyParsing makes is easy to write External DSLs
+ Python makes it easy to write Internal DSLs

More Related Content

What's hot

[pgday.Seoul 2022] PostgreSQL구조 - 윤성재
[pgday.Seoul 2022] PostgreSQL구조 - 윤성재[pgday.Seoul 2022] PostgreSQL구조 - 윤성재
[pgday.Seoul 2022] PostgreSQL구조 - 윤성재PgDay.Seoul
 
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정PgDay.Seoul
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
Developing Microservices with Apache Camel
Developing Microservices with Apache CamelDeveloping Microservices with Apache Camel
Developing Microservices with Apache CamelClaus Ibsen
 
Document Object Model
Document Object ModelDocument Object Model
Document Object Modelchomas kandar
 
Introduction to Javascript By Satyen
Introduction to Javascript By  SatyenIntroduction to Javascript By  Satyen
Introduction to Javascript By SatyenSatyen Pandya
 
jpa-hibernate-presentation
jpa-hibernate-presentationjpa-hibernate-presentation
jpa-hibernate-presentationJohn Slick
 
ReactJS presentation
ReactJS presentationReactJS presentation
ReactJS presentationThanh Tuong
 
Solid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJSSolid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJSRafael Casuso Romate
 
Mongoose and MongoDB 101
Mongoose and MongoDB 101Mongoose and MongoDB 101
Mongoose and MongoDB 101Will Button
 
JavaScript - Chapter 12 - Document Object Model
  JavaScript - Chapter 12 - Document Object Model  JavaScript - Chapter 12 - Document Object Model
JavaScript - Chapter 12 - Document Object ModelWebStackAcademy
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring DataArturs Drozdovs
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정Arawn Park
 
Introduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examplesIntroduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examplesecosio GmbH
 

What's hot (20)

[pgday.Seoul 2022] PostgreSQL구조 - 윤성재
[pgday.Seoul 2022] PostgreSQL구조 - 윤성재[pgday.Seoul 2022] PostgreSQL구조 - 윤성재
[pgday.Seoul 2022] PostgreSQL구조 - 윤성재
 
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
[pgday.Seoul 2022] 서비스개편시 PostgreSQL 도입기 - 진소린 & 김태정
 
Introduction to the DOM
Introduction to the DOMIntroduction to the DOM
Introduction to the DOM
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
Developing Microservices with Apache Camel
Developing Microservices with Apache CamelDeveloping Microservices with Apache Camel
Developing Microservices with Apache Camel
 
Up to Speed on HTML 5 and CSS 3
Up to Speed on HTML 5 and CSS 3Up to Speed on HTML 5 and CSS 3
Up to Speed on HTML 5 and CSS 3
 
Document Object Model
Document Object ModelDocument Object Model
Document Object Model
 
Introduction to Javascript By Satyen
Introduction to Javascript By  SatyenIntroduction to Javascript By  Satyen
Introduction to Javascript By Satyen
 
jpa-hibernate-presentation
jpa-hibernate-presentationjpa-hibernate-presentation
jpa-hibernate-presentation
 
ReactJS presentation
ReactJS presentationReactJS presentation
ReactJS presentation
 
Solid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJSSolid NodeJS with TypeScript, Jest & NestJS
Solid NodeJS with TypeScript, Jest & NestJS
 
Java 8 Lambda and Streams
Java 8 Lambda and StreamsJava 8 Lambda and Streams
Java 8 Lambda and Streams
 
Introduction to XML
Introduction to XMLIntroduction to XML
Introduction to XML
 
Mongoose and MongoDB 101
Mongoose and MongoDB 101Mongoose and MongoDB 101
Mongoose and MongoDB 101
 
JavaScript - Chapter 12 - Document Object Model
  JavaScript - Chapter 12 - Document Object Model  JavaScript - Chapter 12 - Document Object Model
JavaScript - Chapter 12 - Document Object Model
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 
Xslt
XsltXslt
Xslt
 
이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정이벤트 기반 분산 시스템을 향한 여정
이벤트 기반 분산 시스템을 향한 여정
 
Introduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examplesIntroduction to JPA and Hibernate including examples
Introduction to JPA and Hibernate including examples
 
Express JS
Express JSExpress JS
Express JS
 

Viewers also liked

150928 - Verisign Public DNS
150928 - Verisign Public DNS150928 - Verisign Public DNS
150928 - Verisign Public DNSMichael Kaczmarek
 
A Designated ENUM DNS Zone Provisioning Architecture
A Designated ENUM DNS Zone Provisioning ArchitectureA Designated ENUM DNS Zone Provisioning Architecture
A Designated ENUM DNS Zone Provisioning Architectureenumplatform
 
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;Barry Greene
 
DNS and Troubleshooting DNS issues in Linux
DNS and Troubleshooting DNS issues in LinuxDNS and Troubleshooting DNS issues in Linux
DNS and Troubleshooting DNS issues in LinuxKonkona Basu
 
I Have the Power(View)
I Have the Power(View)I Have the Power(View)
I Have the Power(View)Will Schroeder
 
IoT Security in Action - Boston Sept 2015
IoT Security in Action - Boston Sept 2015IoT Security in Action - Boston Sept 2015
IoT Security in Action - Boston Sept 2015Eurotech
 
Query-name Minimization and Authoritative Server Behavior
Query-name Minimization and Authoritative Server BehaviorQuery-name Minimization and Authoritative Server Behavior
Query-name Minimization and Authoritative Server BehaviorShumon Huque
 
Hands-on getdns Tutorial
Hands-on getdns TutorialHands-on getdns Tutorial
Hands-on getdns TutorialShumon Huque
 
Approaches to application request throttling
Approaches to application request throttlingApproaches to application request throttling
Approaches to application request throttlingMaarten Balliauw
 
Are you ready for the next attack? reviewing the sp security checklist (apnic...
Are you ready for the next attack? reviewing the sp security checklist (apnic...Are you ready for the next attack? reviewing the sp security checklist (apnic...
Are you ready for the next attack? reviewing the sp security checklist (apnic...Barry Greene
 
Indusrty Strategy For Action
Indusrty Strategy For ActionIndusrty Strategy For Action
Indusrty Strategy For ActionBarry Greene
 
OpenDNS Enterprise Web Content Filtering
OpenDNS Enterprise Web Content FilteringOpenDNS Enterprise Web Content Filtering
OpenDNS Enterprise Web Content FilteringOpenDNS
 
Remediating Violated Customers
Remediating Violated CustomersRemediating Violated Customers
Remediating Violated CustomersBarry Greene
 
DNS for Developers - NDC Oslo 2016
DNS for Developers - NDC Oslo 2016DNS for Developers - NDC Oslo 2016
DNS for Developers - NDC Oslo 2016Maarten Balliauw
 

Viewers also liked (20)

Managing Postgres with Ansible
Managing Postgres with AnsibleManaging Postgres with Ansible
Managing Postgres with Ansible
 
Network security
Network securityNetwork security
Network security
 
150928 - Verisign Public DNS
150928 - Verisign Public DNS150928 - Verisign Public DNS
150928 - Verisign Public DNS
 
A Designated ENUM DNS Zone Provisioning Architecture
A Designated ENUM DNS Zone Provisioning ArchitectureA Designated ENUM DNS Zone Provisioning Architecture
A Designated ENUM DNS Zone Provisioning Architecture
 
IDNOG - 2014
IDNOG - 2014IDNOG - 2014
IDNOG - 2014
 
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;
BIND’s New Security Feature: DNSRPZ - the &quot;DNS Firewall&quot;
 
TTÜ Geeky Weekly
TTÜ Geeky WeeklyTTÜ Geeky Weekly
TTÜ Geeky Weekly
 
DNS and Troubleshooting DNS issues in Linux
DNS and Troubleshooting DNS issues in LinuxDNS and Troubleshooting DNS issues in Linux
DNS and Troubleshooting DNS issues in Linux
 
I Have the Power(View)
I Have the Power(View)I Have the Power(View)
I Have the Power(View)
 
IoT Security in Action - Boston Sept 2015
IoT Security in Action - Boston Sept 2015IoT Security in Action - Boston Sept 2015
IoT Security in Action - Boston Sept 2015
 
Query-name Minimization and Authoritative Server Behavior
Query-name Minimization and Authoritative Server BehaviorQuery-name Minimization and Authoritative Server Behavior
Query-name Minimization and Authoritative Server Behavior
 
Hands-on getdns Tutorial
Hands-on getdns TutorialHands-on getdns Tutorial
Hands-on getdns Tutorial
 
Approaches to application request throttling
Approaches to application request throttlingApproaches to application request throttling
Approaches to application request throttling
 
PostgreSQL DBA Neler Yapar?
PostgreSQL DBA Neler Yapar?PostgreSQL DBA Neler Yapar?
PostgreSQL DBA Neler Yapar?
 
PostgreSQL Hem Güçlü Hem Güzel!
PostgreSQL Hem Güçlü Hem Güzel!PostgreSQL Hem Güçlü Hem Güzel!
PostgreSQL Hem Güçlü Hem Güzel!
 
Are you ready for the next attack? reviewing the sp security checklist (apnic...
Are you ready for the next attack? reviewing the sp security checklist (apnic...Are you ready for the next attack? reviewing the sp security checklist (apnic...
Are you ready for the next attack? reviewing the sp security checklist (apnic...
 
Indusrty Strategy For Action
Indusrty Strategy For ActionIndusrty Strategy For Action
Indusrty Strategy For Action
 
OpenDNS Enterprise Web Content Filtering
OpenDNS Enterprise Web Content FilteringOpenDNS Enterprise Web Content Filtering
OpenDNS Enterprise Web Content Filtering
 
Remediating Violated Customers
Remediating Violated CustomersRemediating Violated Customers
Remediating Violated Customers
 
DNS for Developers - NDC Oslo 2016
DNS for Developers - NDC Oslo 2016DNS for Developers - NDC Oslo 2016
DNS for Developers - NDC Oslo 2016
 

Similar to Creating Domain Specific Languages in Python

Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languagesArthur Xavier
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairMark
 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksShawn Rider
 
Pxb For Yapc2008
Pxb For Yapc2008Pxb For Yapc2008
Pxb For Yapc2008maximgrp
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter InternalsPedro Medeiros
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceMaarten Balliauw
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala Knoldus Inc.
 
Processing XML and Spreadsheet data in Go
Processing XML and Spreadsheet data in GoProcessing XML and Spreadsheet data in Go
Processing XML and Spreadsheet data in GoRi Xu
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysqlKnoldus Inc.
 
CS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesCS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesEelco Visser
 
Attributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active recordAttributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active record.toster
 
Using Scala Slick at FortyTwo
Using Scala Slick at FortyTwoUsing Scala Slick at FortyTwo
Using Scala Slick at FortyTwoEishay Smith
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Workhorse Computing
 

Similar to Creating Domain Specific Languages in Python (20)

Type safe embedded domain-specific languages
Type safe embedded domain-specific languagesType safe embedded domain-specific languages
Type safe embedded domain-specific languages
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love Affair
 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, Tricks
 
DataMapper
DataMapperDataMapper
DataMapper
 
Clean code
Clean codeClean code
Clean code
 
Pxb For Yapc2008
Pxb For Yapc2008Pxb For Yapc2008
Pxb For Yapc2008
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter Internals
 
Building a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to Space
 
Functions In Scala
Functions In Scala Functions In Scala
Functions In Scala
 
Processing XML and Spreadsheet data in Go
Processing XML and Spreadsheet data in GoProcessing XML and Spreadsheet data in Go
Processing XML and Spreadsheet data in Go
 
Form demoinplaywithmysql
Form demoinplaywithmysqlForm demoinplaywithmysql
Form demoinplaywithmysql
 
Moodle Quick Forms
Moodle Quick FormsMoodle Quick Forms
Moodle Quick Forms
 
CS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic ServicesCS4200 2019 | Lecture 4 | Syntactic Services
CS4200 2019 | Lecture 4 | Syntactic Services
 
Rails <form> Chronicle
Rails <form> ChronicleRails <form> Chronicle
Rails <form> Chronicle
 
Attributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active recordAttributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active record
 
Framework
FrameworkFramework
Framework
 
Using Scala Slick at FortyTwo
Using Scala Slick at FortyTwoUsing Scala Slick at FortyTwo
Using Scala Slick at FortyTwo
 
Python basic
Python basicPython basic
Python basic
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
 

More from Siddhi

Not all features are equal
Not all features are equalNot all features are equal
Not all features are equalSiddhi
 
The end of the backlog?
The end of the backlog?The end of the backlog?
The end of the backlog?Siddhi
 
Growth hacks
Growth hacksGrowth hacks
Growth hacksSiddhi
 
Kanban for Startups
Kanban for StartupsKanban for Startups
Kanban for StartupsSiddhi
 
Venture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market surveyVenture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market surveySiddhi
 
Technology Entrepreneurship: Assignment 2
Technology Entrepreneurship: Assignment 2Technology Entrepreneurship: Assignment 2
Technology Entrepreneurship: Assignment 2Siddhi
 
5 steps to better user engagement
5 steps to better user engagement5 steps to better user engagement
5 steps to better user engagementSiddhi
 
Bridging the gap between your Agile project organisation and the traditional ...
Bridging the gap between your Agile project organisation and the traditional ...Bridging the gap between your Agile project organisation and the traditional ...
Bridging the gap between your Agile project organisation and the traditional ...Siddhi
 
So you wanna build something? Now what?
So you wanna build something? Now what?So you wanna build something? Now what?
So you wanna build something? Now what?Siddhi
 
Agile in short projects
Agile in short projectsAgile in short projects
Agile in short projectsSiddhi
 
Continuous feedback
Continuous feedbackContinuous feedback
Continuous feedbackSiddhi
 
Organizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the RescueOrganizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the RescueSiddhi
 
Agile is not the easy way out
Agile is not the easy way outAgile is not the easy way out
Agile is not the easy way outSiddhi
 
The Three Amigos
The Three AmigosThe Three Amigos
The Three AmigosSiddhi
 
Visualisation & Self Organisation
Visualisation & Self OrganisationVisualisation & Self Organisation
Visualisation & Self OrganisationSiddhi
 
Portfolio Management - Figuring Out How to Say When and Why
Portfolio Management - Figuring Out How to Say When and WhyPortfolio Management - Figuring Out How to Say When and Why
Portfolio Management - Figuring Out How to Say When and WhySiddhi
 
Attention Middle Management Chickens
Attention Middle Management ChickensAttention Middle Management Chickens
Attention Middle Management ChickensSiddhi
 
Agile Project Outsourcing - Dealing with RFP and RFI
Agile Project Outsourcing - Dealing with RFP and RFIAgile Project Outsourcing - Dealing with RFP and RFI
Agile Project Outsourcing - Dealing with RFP and RFISiddhi
 
Migrating Legacy Code
Migrating Legacy CodeMigrating Legacy Code
Migrating Legacy CodeSiddhi
 
Big Bang Agile Roll-out
Big Bang Agile Roll-outBig Bang Agile Roll-out
Big Bang Agile Roll-outSiddhi
 

More from Siddhi (20)

Not all features are equal
Not all features are equalNot all features are equal
Not all features are equal
 
The end of the backlog?
The end of the backlog?The end of the backlog?
The end of the backlog?
 
Growth hacks
Growth hacksGrowth hacks
Growth hacks
 
Kanban for Startups
Kanban for StartupsKanban for Startups
Kanban for Startups
 
Venture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market surveyVenture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market survey
 
Technology Entrepreneurship: Assignment 2
Technology Entrepreneurship: Assignment 2Technology Entrepreneurship: Assignment 2
Technology Entrepreneurship: Assignment 2
 
5 steps to better user engagement
5 steps to better user engagement5 steps to better user engagement
5 steps to better user engagement
 
Bridging the gap between your Agile project organisation and the traditional ...
Bridging the gap between your Agile project organisation and the traditional ...Bridging the gap between your Agile project organisation and the traditional ...
Bridging the gap between your Agile project organisation and the traditional ...
 
So you wanna build something? Now what?
So you wanna build something? Now what?So you wanna build something? Now what?
So you wanna build something? Now what?
 
Agile in short projects
Agile in short projectsAgile in short projects
Agile in short projects
 
Continuous feedback
Continuous feedbackContinuous feedback
Continuous feedback
 
Organizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the RescueOrganizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the Rescue
 
Agile is not the easy way out
Agile is not the easy way outAgile is not the easy way out
Agile is not the easy way out
 
The Three Amigos
The Three AmigosThe Three Amigos
The Three Amigos
 
Visualisation & Self Organisation
Visualisation & Self OrganisationVisualisation & Self Organisation
Visualisation & Self Organisation
 
Portfolio Management - Figuring Out How to Say When and Why
Portfolio Management - Figuring Out How to Say When and WhyPortfolio Management - Figuring Out How to Say When and Why
Portfolio Management - Figuring Out How to Say When and Why
 
Attention Middle Management Chickens
Attention Middle Management ChickensAttention Middle Management Chickens
Attention Middle Management Chickens
 
Agile Project Outsourcing - Dealing with RFP and RFI
Agile Project Outsourcing - Dealing with RFP and RFIAgile Project Outsourcing - Dealing with RFP and RFI
Agile Project Outsourcing - Dealing with RFP and RFI
 
Migrating Legacy Code
Migrating Legacy CodeMigrating Legacy Code
Migrating Legacy Code
 
Big Bang Agile Roll-out
Big Bang Agile Roll-outBig Bang Agile Roll-out
Big Bang Agile Roll-out
 

Recently uploaded

FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...apidays
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusZilliz
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbuapidays
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 

Recently uploaded (20)

FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 

Creating Domain Specific Languages in Python

  • 1. Domain Specific Languages in Python Siddharta Govindaraj siddharta@silverstripesoftware.com
  • 2. What are DSLs? Specialized mini-languages for specific problem domains that make it easier to work in that domain
  • 3. Example: SQL SQL is a mini language specialized to retrieve data from a relational database
  • 4. Example: Regular Expressions Regular Expressions are mini languages specialized to express string patterns to match
  • 5. Life Without Regular Expressions def is_ip_address(ip_address): components = ip_address_string.split(".") if len(components) != 4: return False try: int_components = [int(component) for component in components] except ValueError: return False for component in int_components: if component < 0 or component > 255: return False return True
  • 6. Life With Regular Expressions def is_ip(ip_address_string): match = re.match(r"^(d{1,3}).(d{1,3}).(d{1,3}). (d{1,3})$", ip_address_string) if not match: return False for component in match.groups(): if int(component) < 0 or int(component) > 255: return False return True
  • 7. The DSL that simplifies our life ^(d{1,3}).(d{1,3}).(d{1,3}).(d{1,3})$
  • 8. Why DSL - Answered When working in a particular domain, write your code in a syntax that fits the domain. When working with patterns, use RegEx When working with RDBMS, use SQL When working in your domain – create your own DSL
  • 9. The two types of DSLs External DSL – The code is written in an external file or as a string, which is read and parsed by the application
  • 10. The two types of DSLs Internal DSL – Use features of the language (like metaclasses) to enable people to write code in python that resembles the domain syntax
  • 11. Creating Forms – No DSL <form> <label>Name:</label><input type=”text” name=”name”/> <label>Email:</label><input type=”text” name=”email”/> <label>Password:</label><input type=”password” name=”name”/> </form>
  • 12. Creating Forms – No DSL – Requires HTML knowledge to maintain – Therefore it is not possible for the end user to change the structure of the form by themselves
  • 13. Creating Forms – External DSL UserForm name->CharField label:Username email->EmailField label:Email Address password->PasswordField This text file is parsed and rendered by the app
  • 14. Creating Forms – External DSL + Easy to understand form structure + Can be easily edited by end users – Requires you to read and parse the file
  • 15. Creating Forms – Internal DSL class UserForm(forms.Form): username = forms.RegexField(regex=r'^w+$', max_length=30) email = forms.EmailField(maxlength=75) password = forms.CharField(widget=forms.PasswordInput()) Django uses metaclass magic to convert this syntax to an easily manipulated python class
  • 16. Creating Forms – Internal DSL + Easy to understand form structure + Easy to work with the form as it is regular python + No need to read and parse the file – Cannot be used by non-programmers – Can sometimes be complicated to implement – Behind the scenes magic → debugging hell
  • 17. Creating an External DSL UserForm name:CharField -> label:Username size:25 email:EmailField -> size:32 password:PasswordField Lets write code to parse and render this form
  • 18. Options for Parsing Using string functions → You have to be crazy Using regular expressions → Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. - Jamie Zawinski Writing a parser → ✓ (we will use PyParsing)
  • 19. Step 1: Get PyParsing pip install pyparsing
  • 20. Step 2: Design the Grammar form ::= form_name newline field+ field ::= field_name colon field_type [arrow property+] property ::= key colon value form_name ::= word field_name ::= word field_type ::= CharField | EmailField | PasswordField key ::= word value ::= alphanumeric+ word ::= alpha+ newline ::= n colon ::= : arrow ::= ->
  • 21. Quick Note Backus-Naur Form (BNF) is a syntax for specifying grammers
  • 22. Step 3: Implement the Grammar newline = "n" colon = ":" arrow = "->" word = Word(alphas) key = word value = Word(alphanums) field_type = oneOf("CharField EmailField PasswordField") field_name = word form_name = word field_property = key + colon + value field = field_name + colon + field_type + Optional(arrow + OneOrMore(field_property)) + newline form = form_name + newline + OneOrMore(field)
  • 23. Quick Note PyParsing itself implements a neat little internal DSL for you to describe the parser grammer Notice how the PyParsing code almost perfectly reflects the BNF grammer
  • 24. Output > print form.parseString(input_form) ['UserForm', 'n', 'name', ':', 'CharField', '->', 'label', ':', 'Username', 'size', ':', '25', 'n', 'email', ':', 'EmailField', '->', 'size', ':', '25', 'n', 'password', ':', 'PasswordField', 'n'] PyParsing has neatly parsed our form input into tokens. Thats nice, but we can do more.
  • 25. Step 4: Suppressing Noise Tokens newline = Suppress("n") colon = Suppress(":") arrow = Suppress("->")
  • 26. Output > print form.parseString(input_form) ['UserForm', 'name', 'CharField', 'label', 'Username', 'size', '25', 'email', 'EmailField', 'size', '25', 'password', 'PasswordField'] All the noise tokens are now removed from the parsed output
  • 27. Step 5: Grouping Tokens field_property = Group(key + colon + value) field = Group(field_name + colon + field_type + Group(Optional(arrow + OneOrMore(field_property))) + newline)
  • 28. Output > print form.parseString(input_form) ['UserForm', ['name', 'CharField', [['label', 'Username'], ['size', '25']]], ['email', 'EmailField', [['size', '25']]], ['password', 'PasswordField',[]]] Related tokens are now grouped together in a list
  • 29. Step 6: Give Names to Tokens form_name = word.setResultsName("form_name") field = Group(field_name + colon + field_type + Group(Optional(arrow + OneOrMore(field_property))) + newline).setResultsName("form_field")
  • 30. Output > parsed_form = form.parseString(input_form) > print parsed_form.form_name UserForm > print parsed_form.fields[1].field_type EmailField Now we can refer to parsed tokens by name
  • 31. Step 7: Convert Properties to Dict def convert_prop_to_dict(tokens): prop_dict = {} for token in tokens: prop_dict[token.property_key] = token.property_value return prop_dict field = Group(field_name + colon + field_type + Optional(arrow + OneOrMore(field_property)) .setParseAction(convert_prop_to_dict) + newline).setResultsName("form_field")
  • 32. Output > print form.parseString(input_form) ['UserForm', ['name', 'CharField', {'size': '25', 'label': 'Username'}], ['email', 'EmailField', {'size': '32'}], ['password', 'PasswordField', {}] ] Sweet! The field properties are parsed into a dict
  • 33. Step 7: Generate HTML Output We need to walk through the parsed form and generate a html string out of it
  • 34. def get_field_html(field): properties = field[2] label = properties["label"] if "label" in properties else field.field_name label_html = "<label>" + label + "</label>" attributes = {"name":field.field_name} attributes.update(properties) if field.field_type == "CharField" or field.field_type == "EmailField": attributes["type"] = "text" else: attributes["type"] = "password" if "label" in attributes: del attributes["label"] attributes_html = " ".join([name+"='"+value+"'" for name,value in attributes.items()]) field_html = "<input " + attributes_html + "/>" return label_html + field_html + "<br/>" def render(form): fields_html = "".join([get_field_html(field) for field in form.fields]) return "<form id='" + form.form_name.lower() +"'>" + fields_html + "</form>"
  • 35. Output > print render(form.parseString(input_form)) <form id='userform'> <label>Username</label> <input type='text' name='name' size='25'/><br/> <label>email</label> <input type='text' name='email' size='32'/><br/> <label>password</label> <input type='password' name='password'/><br/> </form>
  • 36. It works, but.... Yuck! The output rendering code is an UGLY MESS
  • 37. Wish we could do this... > print Form(CharField(name=”user”,size=”25”,label=”ID”), id=”myform”) <form id='myform'> <label>ID</label> <input type='text' name='name' size='25'/><br/> </form> Neat, clean syntax that matches the output domain well. But how do we create this kind of syntax?
  • 38. Lets create an Internal DSL
  • 39. class HtmlElement(object): default_attributes = {} tag = "unknown_tag" def __init__(self, *args, **kwargs): self.attributes = kwargs self.attributes.update(self.default_attributes) self.children = args def __str__(self): attribute_html = " ".join(["{}='{}'".format(name, value) for name,value in self.attributes.items()]) if not self.children: return "<{} {}/>".format(self.tag, attribute_html) else: children_html = "".join([str(child) for child in self.children]) return "<{} {}>{}</{}>".format(self.tag, attribute_html, children_html, self.tag)
  • 40. > print HtmlElement(id=”test”) <unknown_tag id='test'/> > print HtmlElement(HtmlElement(name=”test”), id=”id”) <unknown_tag id='id'><unknown_tag name='test'/></unknown_tag>
  • 41. class Input(HtmlElement): tag = "input" def __init__(self, *args, **kwargs): HtmlElement.__init__(self, *args, **kwargs) self.label = self.attributes["label"] if "label" in self.attributes else self.attributes["name"] if "label" in self.attributes: del self.attributes["label"] def __str__(self): label_html = "<label>{}</label>".format(self.label) return label_html + HtmlElement.__str__(self) + "<br/>"
  • 42. > print InputElement(name=”username”) <label>username</label><input name='username'/><br/> > print InputElement(name=”username”, label=”User ID”) <label>User ID</label><input name='username'/><br/>
  • 43. class Form(HtmlElement): tag = "form" class CharField(Input): default_attributes = {"type":"text"} class EmailField(CharField): pass class PasswordField(Input): default_attributes = {"type":"password"}
  • 44. Now... > print Form(CharField(name=”user”,size=”25”,label=”ID”), id=”myform”) <form id='myform'> <label>ID</label> <input type='text' name='name' size='25'/><br/> </form> Nice!
  • 45. Step 7 Revisited: Output HTML def render(form): field_dict = {"CharField": CharField, "EmailField": EmailField, "PasswordField": PasswordField} fields = [field_dict[field.field_type] (name=field.field_name, **field[2]) for field in form.fields] return Form(*fields, id=form.form_name.lower()) Now our output code uses our Internal DSL!
  • 46. INPUT UserForm name:CharField -> label:Username size:25 email:EmailField -> size:32 password:PasswordField OUTPUT <form id='userform'> <label>Username</label> <input type='text' name='name' size='25'/><br/> <label>email</label> <input type='text' name='email' size='32'/><br/> <label>password</label> <input type='password' name='password'/><br/> </form>
  • 47. Get the whole code http://bit.ly/pyconindia_dsl
  • 48. Summary + DSLs make your code easier to read + DSLs make your code easier to write + DSLs make it easy to for non-programmers to maintain code + PyParsing makes is easy to write External DSLs + Python makes it easy to write Internal DSLs