Welcome, guest | Sign In | My Account | Store | Cart

is a very simple templating-system. the goals of this 'system' were - easy to use and to learn cheetah and yaptu for example was much to complex to install and learn and did a lot of things i didnt need. - easy to change. blender is going to be used and serviced by python newbies. there is absolutely no chance to have something like complex regexes, evaluation or automatically including the namespaces and the like. - much cooler name than 'yaptu' ;-)

Python, 126 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import types

class Blender:
    """blends values into the given pattern.replace
        if neither values nor pattern are defined a default
        pattern is being created that prints the values of
        the instance in the format [name1: value1, name2 = value2, ...]
        """

    def __init__(self, pattern = None, values = None,
                 startToken = "${", endToken = "}"):
        """initializes the instance with defaultvalues.
        that is the start and the end token
        """
        self.BlendPattern = pattern
        self.BlendValues = values
        self.StartToken = startToken
        self.EndToken = endToken

    def blend(self, values = None, pattern = None):
        """blends the values into the given pattern"""
        values = self.getValues(values)
        pattern = self.getPattern(pattern, values)
        for name in values.keys():
            id = self.getTokenName(name)
            value = values[name]
            pattern = pattern.replace(id, str(value))
        return pattern

    def getValues(self, values):
        """ returns the dictionary of values.
            if no values are supplied this
            instance is returned as a dictionary."""
        if values == None:
            if self.BlendValues == None:
                values = self.__dict__
            else:
                values = self.BlendValues
        if type(values) != types.DictionaryType:
            values = values.__dict__
        return values

    def getBasePattern(self, values):
        """returns a pattern in the format
            [name1: value1, name2: value2, ...]
            excluding the instance-attributes of this class
            """
        names = values.keys()
        names.sort()
        result = "["
        for name in names:
            if name not in ["BlendPattern",
                            "BlendValues",
                            "StartToken",
                            "EndToken"]:
                result += name + ": " + self.getTokenName(name) + ", "
        return result[0:-2] + "]"

    def getPattern(self, pattern, values):
        """returns a pattern for this instance. if no pattern is defined
            returns a default-pattern.
            """
        if pattern == None:
            if self.BlendPattern == None:
                pattern = self.getBasePattern(values)
            else:
                pattern = self.BlendPattern
        return pattern

    def getTokenName(self, name):
        """returns the tokenname bound by the start and end token.
        """
        return self.StartToken + name + self.EndToken

    def __str__(self):
        return self.blend()

class Person(Blender):
    def __init__(self, name, lastName):
        Blender.__init__(self)
        self.Name = name
        self.LastName = lastName

class User(Person):
    def __init__(self, id, name, lastName):
        Person.__init__(self, name, lastName)
        self.ID = id

class Login(Blender):
    def __init__(self):
        Blender.__init__(self)
        self.BlendPattern = """
            Hello ${Name} ${LastName}!
            Your Userid is: ${ID}.
            You are logged into domain ${Domain}.
        """

class UserQuery(Blender):
    def __init__(self, values):
        pattern = """
            SELECT *
            FROM User
            WHERE
                id = ${ID} AND
                domain like '${Domain}'
            """
        Blender.__init__(self, pattern, values)

if __name__ == "__main__":
    p = Person("Robert", "Kuzelj")
    print p

    u = User("007", "Robert", "Kuzelj")
    print u

    login = Login()
    login.Name = "Robert"
    login.LastName = "Kuzelj"
    login.ID = 7
    login.Domain = "python.org"
    print login
    
    sql = "SELECT * from User WHERE id=:{ID} AND domain like ':{Domain}'"
    print Blender(sql, {"Domain": "python.org", "ID": "007"}, ":{", "}")

    print UserQuery(login)

this class was mainly motivated due the fact, that i had a lot of small and medium value-classes i needed to trace. the output was meant to be easy to digest (sometimes the need arose to process the output) and the layout was meant to be easyly changed.

the second force that made me do it (except for the usual suspects ) was the need to have a simple variable replacement-system for dynamic sql-statements.

since my code had to be serviced by relativly new python/OO people i decided not to use cheetah or any other templatingsystem. cause every lib a looked at was - either hard to install - hard to learn - almost everytime hard to change (say impossible) - did stuff i did not need (complex regexes) - or did all the things above i am convinced that it is ideally suited to peoble with modest python knowhow beginning to explore the dynamic nature of python.

EXTENSIONS one thing i was thinkink about was to make blender even more 'declarative' by using the docstring of the declaring class.

something similar to this would then be possible

class UserQuery(Blender): """ SELECT * FROM User WHERE id = ${ID} AND domain like '${Domain}' """

no definition of an constructor no calling of baseconstrutors... on the other hand this would make the inner workings of blender harder to grasp and simplicity was one of the major goals.

2 comments

Drew Perttula 22 years, 1 month ago  # | flag

advantage over % ? I'm not seeing the advantage over python's own % operator. If you used %( and )s for the "start and end tokens", the % operator will easily interpolate in a dictionary of replacements.

"SELECT * from User WHERE id=%(ID)s AND domain like '%(Domain)s'" % { "Domain": "python.org", "ID": "007" }

gives

"SELECT * from User WHERE id=007 AND domain like 'python.org'"

and it's already available in all python programs.

robert kuzelj (author) 22 years, 1 month ago  # | flag

oops,

this was defenitly a case of rtfm on my side. didnt know, that this is possible.

so the only advantage might be to have a automatic representation of an object (not very much i admit)

ciao robertj

Created by robert kuzelj on Mon, 4 Feb 2002 (PSF)
Python recipes (4591)
robert kuzelj's recipes (1)

Required Modules

Other Information and Tasks