SlideShare ist ein Scribd-Unternehmen logo
1 von 48
Downloaden Sie, um offline zu lesen
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

Weitere Àhnliche Inhalte

Was ist angesagt?

Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
Spark Summit
 
elasticsearch_적용 및 활용_ì •ëŠŹ
elasticsearch_적용 및 활용_ì •ëŠŹelasticsearch_적용 및 활용_ì •ëŠŹ
elasticsearch_적용 및 활용_ì •ëŠŹ
Junyi Song
 
Building Robust Production Data Pipelines with Databricks Delta
Building Robust Production Data Pipelines with Databricks DeltaBuilding Robust Production Data Pipelines with Databricks Delta
Building Robust Production Data Pipelines with Databricks Delta
Databricks
 

Was ist angesagt? (20)

Percona Xtrabackup - Highly Efficient Backups
Percona Xtrabackup - Highly Efficient BackupsPercona Xtrabackup - Highly Efficient Backups
Percona Xtrabackup - Highly Efficient Backups
 
Apache Hive Hook
Apache Hive HookApache Hive Hook
Apache Hive Hook
 
InfluxDB IOx Tech Talks: Query Processing in InfluxDB IOx
InfluxDB IOx Tech Talks: Query Processing in InfluxDB IOxInfluxDB IOx Tech Talks: Query Processing in InfluxDB IOx
InfluxDB IOx Tech Talks: Query Processing in InfluxDB IOx
 
Protect your private data with ORC column encryption
Protect your private data with ORC column encryptionProtect your private data with ORC column encryption
Protect your private data with ORC column encryption
 
Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
Spark as a Platform to Support Multi-Tenancy and Many Kinds of Data Applicati...
 
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
How to successfully manage a ZIO fiber’s lifecycle - Functional Scala 2021
 
elasticsearch_적용 및 활용_ì •ëŠŹ
elasticsearch_적용 및 활용_ì •ëŠŹelasticsearch_적용 및 활용_ì •ëŠŹ
elasticsearch_적용 및 활용_ì •ëŠŹ
 
Big data-cheat-sheet
Big data-cheat-sheetBig data-cheat-sheet
Big data-cheat-sheet
 
Best Practices for Using Apache Spark on AWS
Best Practices for Using Apache Spark on AWSBest Practices for Using Apache Spark on AWS
Best Practices for Using Apache Spark on AWS
 
Building Robust Production Data Pipelines with Databricks Delta
Building Robust Production Data Pipelines with Databricks DeltaBuilding Robust Production Data Pipelines with Databricks Delta
Building Robust Production Data Pipelines with Databricks Delta
 
Pyspark Tutorial | Introduction to Apache Spark with Python | PySpark Trainin...
Pyspark Tutorial | Introduction to Apache Spark with Python | PySpark Trainin...Pyspark Tutorial | Introduction to Apache Spark with Python | PySpark Trainin...
Pyspark Tutorial | Introduction to Apache Spark with Python | PySpark Trainin...
 
Parquet Hadoop Summit 2013
Parquet Hadoop Summit 2013Parquet Hadoop Summit 2013
Parquet Hadoop Summit 2013
 
Processing Large Data with Apache Spark -- HasGeek
Processing Large Data with Apache Spark -- HasGeekProcessing Large Data with Apache Spark -- HasGeek
Processing Large Data with Apache Spark -- HasGeek
 
Cost-based Query Optimization in Apache Phoenix using Apache Calcite
Cost-based Query Optimization in Apache Phoenix using Apache CalciteCost-based Query Optimization in Apache Phoenix using Apache Calcite
Cost-based Query Optimization in Apache Phoenix using Apache Calcite
 
Domain Driven Design Made Functional with Python
Domain Driven Design Made Functional with Python Domain Driven Design Made Functional with Python
Domain Driven Design Made Functional with Python
 
C* Summit 2013: How Not to Use Cassandra by Axel Liljencrantz
C* Summit 2013: How Not to Use Cassandra by Axel LiljencrantzC* Summit 2013: How Not to Use Cassandra by Axel Liljencrantz
C* Summit 2013: How Not to Use Cassandra by Axel Liljencrantz
 
Streaming Data Lakes using Kafka Connect + Apache Hudi | Vinoth Chandar, Apac...
Streaming Data Lakes using Kafka Connect + Apache Hudi | Vinoth Chandar, Apac...Streaming Data Lakes using Kafka Connect + Apache Hudi | Vinoth Chandar, Apac...
Streaming Data Lakes using Kafka Connect + Apache Hudi | Vinoth Chandar, Apac...
 
Impacts of Sharding, Partitioning, Encoding, and Sorting on Distributed Query...
Impacts of Sharding, Partitioning, Encoding, and Sorting on Distributed Query...Impacts of Sharding, Partitioning, Encoding, and Sorting on Distributed Query...
Impacts of Sharding, Partitioning, Encoding, and Sorting on Distributed Query...
 
Redis + Apache Spark = Swiss Army Knife Meets Kitchen Sink
Redis + Apache Spark = Swiss Army Knife Meets Kitchen SinkRedis + Apache Spark = Swiss Army Knife Meets Kitchen Sink
Redis + Apache Spark = Swiss Army Knife Meets Kitchen Sink
 
Power BI Interview Questions and Answers | Power BI Certification | Power BI ...
Power BI Interview Questions and Answers | Power BI Certification | Power BI ...Power BI Interview Questions and Answers | Power BI Certification | Power BI ...
Power BI Interview Questions and Answers | Power BI Certification | Power BI ...
 

Andere mochten auch

150928 - Verisign Public DNS
150928 - Verisign Public DNS150928 - Verisign Public DNS
150928 - Verisign Public DNS
Michael 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 Architecture
enumplatform
 
IDNOG - 2014
IDNOG - 2014IDNOG - 2014
IDNOG - 2014
Barry Greene
 
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
 

Andere mochten auch (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
 

Ähnlich wie Creating Domain Specific Languages in Python

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
 

Ähnlich wie 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.
 

Mehr von Siddhi

Venture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market surveyVenture lab tech entrepreneurship market survey
Venture lab tech entrepreneurship market survey
Siddhi
 
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 projects
Siddhi
 
Continuous feedback
Continuous feedbackContinuous feedback
Continuous feedback
Siddhi
 
Organizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the RescueOrganizational Dysfunctions - Agile to the Rescue
Organizational Dysfunctions - Agile to the Rescue
Siddhi
 
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
Siddhi
 
The Three Amigos
The Three AmigosThe Three Amigos
The Three Amigos
Siddhi
 
Visualisation & Self Organisation
Visualisation & Self OrganisationVisualisation & Self Organisation
Visualisation & Self Organisation
Siddhi
 
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
Siddhi
 
Attention Middle Management Chickens
Attention Middle Management ChickensAttention Middle Management Chickens
Attention Middle Management Chickens
Siddhi
 
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
Siddhi
 
Migrating Legacy Code
Migrating Legacy CodeMigrating Legacy Code
Migrating Legacy Code
Siddhi
 
Big Bang Agile Roll-out
Big Bang Agile Roll-outBig Bang Agile Roll-out
Big Bang Agile Roll-out
Siddhi
 

Mehr von 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
 

KĂŒrzlich hochgeladen

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
Christopher Logan Kennedy
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

KĂŒrzlich hochgeladen (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
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, ...
 
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
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
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
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
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
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
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
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 

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