1#!/usr/bin/env python 2 3# Copyright (c) 2010, Google Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: 9# 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above 13# copyright notice, this list of conditions and the following disclaimer 14# in the documentation and/or other materials provided with the 15# distribution. 16# * Neither the name of Google Inc. nor the names of its 17# contributors may be used to endorse or promote products derived from 18# this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32"""Module to enforce different constraints on flags. 33 34A validator represents an invariant, enforced over a one or more flags. 35See 'FLAGS VALIDATORS' in gflags.py's docstring for a usage manual. 36""" 37 38__author__ = 'olexiy@google.com (Olexiy Oryeshko)' 39 40 41class Error(Exception): 42 """Thrown If validator constraint is not satisfied.""" 43 44 45class Validator(object): 46 """Base class for flags validators. 47 48 Users should NOT overload these classes, and use gflags.Register... 49 methods instead. 50 """ 51 52 # Used to assign each validator an unique insertion_index 53 validators_count = 0 54 55 def __init__(self, checker, message): 56 """Constructor to create all validators. 57 58 Args: 59 checker: function to verify the constraint. 60 Input of this method varies, see SimpleValidator and 61 DictionaryValidator for a detailed description. 62 message: string, error message to be shown to the user 63 """ 64 self.checker = checker 65 self.message = message 66 Validator.validators_count += 1 67 # Used to assert validators in the order they were registered (CL/18694236) 68 self.insertion_index = Validator.validators_count 69 70 def Verify(self, flag_values): 71 """Verify that constraint is satisfied. 72 73 flags library calls this method to verify Validator's constraint. 74 Args: 75 flag_values: gflags.FlagValues, containing all flags 76 Raises: 77 Error: if constraint is not satisfied. 78 """ 79 param = self._GetInputToCheckerFunction(flag_values) 80 if not self.checker(param): 81 raise Error(self.message) 82 83 def GetFlagsNames(self): 84 """Return the names of the flags checked by this validator. 85 86 Returns: 87 [string], names of the flags 88 """ 89 raise NotImplementedError('This method should be overloaded') 90 91 def PrintFlagsWithValues(self, flag_values): 92 raise NotImplementedError('This method should be overloaded') 93 94 def _GetInputToCheckerFunction(self, flag_values): 95 """Given flag values, construct the input to be given to checker. 96 97 Args: 98 flag_values: gflags.FlagValues, containing all flags. 99 Returns: 100 Return type depends on the specific validator. 101 """ 102 raise NotImplementedError('This method should be overloaded') 103 104 105class SimpleValidator(Validator): 106 """Validator behind RegisterValidator() method. 107 108 Validates that a single flag passes its checker function. The checker function 109 takes the flag value and returns True (if value looks fine) or, if flag value 110 is not valid, either returns False or raises an Exception.""" 111 def __init__(self, flag_name, checker, message): 112 """Constructor. 113 114 Args: 115 flag_name: string, name of the flag. 116 checker: function to verify the validator. 117 input - value of the corresponding flag (string, boolean, etc). 118 output - Boolean. Must return True if validator constraint is satisfied. 119 If constraint is not satisfied, it should either return False or 120 raise Error. 121 message: string, error message to be shown to the user if validator's 122 condition is not satisfied 123 """ 124 super(SimpleValidator, self).__init__(checker, message) 125 self.flag_name = flag_name 126 127 def GetFlagsNames(self): 128 return [self.flag_name] 129 130 def PrintFlagsWithValues(self, flag_values): 131 return 'flag --%s=%s' % (self.flag_name, flag_values[self.flag_name].value) 132 133 def _GetInputToCheckerFunction(self, flag_values): 134 """Given flag values, construct the input to be given to checker. 135 136 Args: 137 flag_values: gflags.FlagValues 138 Returns: 139 value of the corresponding flag. 140 """ 141 return flag_values[self.flag_name].value 142 143 144class DictionaryValidator(Validator): 145 """Validator behind RegisterDictionaryValidator method. 146 147 Validates that flag values pass their common checker function. The checker 148 function takes flag values and returns True (if values look fine) or, 149 if values are not valid, either returns False or raises an Exception. 150 """ 151 def __init__(self, flag_names, checker, message): 152 """Constructor. 153 154 Args: 155 flag_names: [string], containing names of the flags used by checker. 156 checker: function to verify the validator. 157 input - dictionary, with keys() being flag_names, and value for each 158 key being the value of the corresponding flag (string, boolean, etc). 159 output - Boolean. Must return True if validator constraint is satisfied. 160 If constraint is not satisfied, it should either return False or 161 raise Error. 162 message: string, error message to be shown to the user if validator's 163 condition is not satisfied 164 """ 165 super(DictionaryValidator, self).__init__(checker, message) 166 self.flag_names = flag_names 167 168 def _GetInputToCheckerFunction(self, flag_values): 169 """Given flag values, construct the input to be given to checker. 170 171 Args: 172 flag_values: gflags.FlagValues 173 Returns: 174 dictionary, with keys() being self.lag_names, and value for each key 175 being the value of the corresponding flag (string, boolean, etc). 176 """ 177 return dict([key, flag_values[key].value] for key in self.flag_names) 178 179 def PrintFlagsWithValues(self, flag_values): 180 prefix = 'flags ' 181 flags_with_values = [] 182 for key in self.flag_names: 183 flags_with_values.append('%s=%s' % (key, flag_values[key].value)) 184 return prefix + ', '.join(flags_with_values) 185 186 def GetFlagsNames(self): 187 return self.flag_names 188