source: trunk/src/AdvancedParser.py @ 170

Last change on this file since 170 was 142, checked in by bas, 15 years ago

Addded:

  • src/AdvancedParser.py
File size: 6.2 KB
Line 
1#
2# Author: Dennis Stam
3# Date  : 09-04-2009
4# Desc. : This class allows you use ranges within the given arguments. Very
5#         useful for specifying mutliple hosts. This class extends the
6#         OptionParser class.
7#
8# SVN Info:
9#       $Id: AdvancedParser.py 3667 2009-04-15 12:02:04Z dennis $
10#       $URL: https://subtrac.sara.nl/hpcv/svn/beowulf/trunk/sara_python_modules/AdvancedParser.py $
11#
12from optparse import OptionParser
13import re
14import types
15
16class AdvancedParser(OptionParser):
17        """
18        This class extends from OptionParser, where the method check_values has been
19        overrided.
20
21        In this function a extra parsing is done on the the rest of the arguments. This
22        extra parsing is the creating of multiple hostnames from a pattern/range.
23
24        When a user specifies this argument dr-r[15,17-20]n[1-5,10] then this class
25        returns 24 hosts. Besides using numbers you can also specify lower cased
26        letters from a-z.
27
28        Doctest:
29        >>> parser = AdvancedParser()
30        >>> parser.return_range('12-15,20')
31        [12, 13, 14, 15, '20']
32
33        >>> option, args = parser.parse_args(['dr-r7n[1-5]'])
34        >>> print args
35        ['dr-r7n1', 'dr-r7n2', 'dr-r7n3', 'dr-r7n4', 'dr-r7n5']
36        """
37
38        def return_range(self, string):
39                """
40                This method uses the given numbers and converts them to ranges. When
41                ower cased letters are specified they will be converted to integer
42                ordinal of a one-character string.
43                (ie. a = 97, z = 122)
44
45                The ranges will be return as lists
46                """
47                parts = string.split( ',' )
48                numbers_chars = list()
49                equal_width_length = 0
50
51                for part in parts:
52                        part_range = part.split( '-' )
53                        if len( part_range ) == 2:
54                                try:
55                                        if part_range[0][0] == '0' or part_range[1][0] == '0':
56                                                if len( part_range[0] ) > len( part_range[1] ):
57                                                        equal_width_length = len( part_range[0] )
58                                                else:
59                                                        equal_width_length = len( part_range[1] )
60
61                                        numbers_chars += range( int( part_range[0] ), int( part_range[1] ) + 1 )
62                                except ValueError:
63                                        begin = ord( part_range[0] )
64                                        end = ord( part_range[1] )
65                                        tmplist = list()
66
67                                        if begin > 96 and end < 123:
68                                                tmplist = range( begin, end + 1)
69
70                                                for letter in tmplist:
71                                                        numbers_chars.append( chr( letter ) )
72                        else:
73                                if equal_width_length != 0 and len( part ) > equal_width_length:
74                                        equal_width_length = len( part )
75
76                                numbers_chars.append( part )
77
78                if equal_width_length > 0:
79                        tmplist = list()
80
81                        for number_char in numbers_chars:
82                                try:
83                                        nnum = int( number_char )
84                                        tmplist.append( '%0*d' % (equal_width_length, nnum) )
85                                except ValueError:
86                                        tmplist.append( number_char )
87                       
88                        numbers_chars = tmplist
89
90                return numbers_chars
91
92        def combine( self, pre, post):
93                '''
94                This method is used to combine a possibility of a combination
95                '''
96                if pre == '':
97                        return post
98                else:
99                        return '%s %s' % (pre, post)
100
101        def combinations( self, listin, prefix=''):
102                '''
103                This method creates from the given ranges all possible combinations
104                '''
105                outlist = list()
106
107                if len( listin ) > 1:
108                        for item in listin[0]:
109                                outlist += self.combinations( listin[1:], self.combine( prefix, str( item ) ) )
110                else:
111                        for item in listin[0]:
112                                outlist.append( tuple( self.combine( prefix, str( item ) ).split( ' ') ) )
113
114                return outlist
115
116        def args_parser(self, args):
117                '''
118                This method checks all given extra arguments for the given ranges between the
119                [ and ]
120                '''
121                findregex = re.compile( r'\[([0-9a-z\-,]+)\]', re.VERBOSE )
122                nodenames = list()
123
124                for arg in args:
125                        found = findregex.findall( arg )
126                        ranges = list()
127
128                        if found:
129                                pattern = findregex.sub( '%s', arg )
130
131                                for part in found:
132                                        ranges.append( self.return_range( part ) )
133
134                                combs = self.combinations( ranges )
135
136                                for comb in combs:
137                                        # Here the %s in the pattern are
138                                        # replaced by the correct value
139                                        nodenames.append( pattern % comb )
140                        else:
141                                nodenames.append( arg )
142
143                return nodenames
144
145        def check_values(self, values, args):
146                '''
147                Here we override the default method in OptionParser to
148                enable our extra parsing on the given Arguments
149                '''
150                return values, self.args_parser( args )
151
152if __name__ == "__main__":
153        import doctest
154        print 'Starting doctest'
155        doctest.testmod()
Note: See TracBrowser for help on using the repository browser.