21
21
22
22
23
23
__all__ = [
24
+ 'CompilerVersion' ,
25
+
24
26
'BoolType' ,
25
27
'PathType' ,
26
28
'RegexType' ,
32
34
33
35
# -----------------------------------------------------------------------------
34
36
37
+ class CompilerVersion (object ):
38
+ """Wrapper type around compiler version strings.
39
+ """
40
+
41
+ def __init__ (self , * components ):
42
+ if len (components ) == 1 :
43
+ if isinstance (components [0 ], str ):
44
+ components = components [0 ].split ('.' )
45
+ elif isinstance (components [0 ], (list , tuple )):
46
+ components = components [0 ]
47
+
48
+ if len (components ) == 0 :
49
+ raise ValueError ('compiler version cannot be empty' )
50
+
51
+ self .components = tuple (int (part ) for part in components )
52
+
53
+ def __eq__ (self , other ):
54
+ return self .components == other .components
55
+
56
+ def __str__ (self ):
57
+ return '.' .join ([str (part ) for part in self .components ])
58
+
59
+
60
+ # -----------------------------------------------------------------------------
61
+
62
+ def _repr (cls , args ):
63
+ """Helper function for implementing __repr__ methods on *Type classes.
64
+ """
65
+
66
+ _args = []
67
+ for key , value in args .viewitems ():
68
+ _args .append ('{}={}' .format (key , repr (value )))
69
+
70
+ return '{}({})' .format (type (cls ).__name__ , ', ' .join (_args ))
71
+
72
+
35
73
class BoolType (object ):
36
74
"""Argument type used to validate an input string as a bool-like type.
37
75
Callers are able to override valid true and false values.
@@ -55,26 +93,46 @@ def __call__(self, value):
55
93
else :
56
94
raise ArgumentTypeError ('{} is not a boolean value' .format (value ))
57
95
96
+ def __repr__ (self ):
97
+ return _repr (self , {
98
+ 'true_values' : self ._true_values ,
99
+ 'false_values' : self ._false_values ,
100
+ })
101
+
58
102
59
103
class PathType (object ):
60
104
"""PathType denotes a valid path-like object. When called paths will be
61
105
fully expanded with the option to assert the file or directory referenced
62
106
by the path exists.
63
107
"""
64
108
65
- def __init__ (self , assert_exists = False ):
66
- self .assert_exists = assert_exists
109
+ def __init__ (self , assert_exists = False , assert_executable = False ):
110
+ self ._assert_exists = assert_exists
111
+ self ._assert_executable = assert_executable
67
112
68
113
def __call__ (self , path ):
69
114
path = os .path .expanduser (path )
70
115
path = os .path .abspath (path )
71
116
path = os .path .realpath (path )
72
117
73
- if self .assert_exists :
74
- assert os .path .exists (path )
118
+ if self ._assert_exists and not os .path .exists (path ):
119
+ raise ArgumentTypeError ('{} does not exists' .format (path ))
120
+
121
+ if self ._assert_executable and not PathType ._is_executable (path ):
122
+ raise ArgumentTypeError ('{} is not an executable' .format (path ))
75
123
76
124
return path
77
125
126
+ def __repr__ (self ):
127
+ return _repr (self , {
128
+ 'assert_exists' : self ._assert_exists ,
129
+ 'assert_executable' : self ._assert_executable ,
130
+ })
131
+
132
+ @staticmethod
133
+ def _is_executable (path ):
134
+ return os .path .isfile (path ) and os .access (path , os .X_OK )
135
+
78
136
79
137
class RegexType (object ):
80
138
"""Argument type used to validate an input string against a regular
@@ -90,7 +148,13 @@ def __call__(self, value):
90
148
if matches is None :
91
149
raise ArgumentTypeError (self ._error_message , value )
92
150
93
- return value
151
+ return matches
152
+
153
+ def __repr__ (self ):
154
+ return _repr (self , {
155
+ 'regex' : self ._regex ,
156
+ 'error_message' : self ._error_message ,
157
+ })
94
158
95
159
96
160
class ClangVersionType (RegexType ):
@@ -107,6 +171,12 @@ def __init__(self):
107
171
ClangVersionType .VERSION_REGEX ,
108
172
ClangVersionType .ERROR_MESSAGE )
109
173
174
+ def __call__ (self , value ):
175
+ matches = super (ClangVersionType , self ).__call__ (value )
176
+ components = filter (lambda x : x is not None , matches .group (1 , 2 , 3 , 5 ))
177
+
178
+ return CompilerVersion (components )
179
+
110
180
111
181
class SwiftVersionType (RegexType ):
112
182
"""Argument type used to validate Swift version strings.
@@ -121,6 +191,12 @@ def __init__(self):
121
191
SwiftVersionType .VERSION_REGEX ,
122
192
SwiftVersionType .ERROR_MESSAGE )
123
193
194
+ def __call__ (self , value ):
195
+ matches = super (SwiftVersionType , self ).__call__ (value )
196
+ components = filter (lambda x : x is not None , matches .group (1 , 2 , 4 ))
197
+
198
+ return CompilerVersion (components )
199
+
124
200
125
201
class ShellSplitType (object ):
126
202
"""Parse and split shell arguments into a list of strings. Recognizes `,`
@@ -140,3 +216,6 @@ def __call__(self, value):
140
216
lex .whitespace_split = True
141
217
lex .whitespace += ','
142
218
return list (lex )
219
+
220
+ def __repr__ (self ):
221
+ return _repr (self , {})
0 commit comments