""" Hooks for validating CPython extension source code """ def get_types(strfmt): """ Generate a list of C type names from a PyArg_ParseTuple format string Compare to Python/getargs.c:vgetargs1 """ result = [] i = 0 while i < len(strfmt): c = strfmt[i] simple = {'i':'int', 's':'char *'} if c in simple: result.append(simple[c] + ' *') if c in [':', ';']: break i += 1 return result class CExtensionError(Exception): # Base class for errors discovered by static analysis in C extension code def __init__(self, location): self.location = location def __str__(self): return '%s:%s: %s' % (self.location.file, self.location.line, self._get_desc()) def _get_desc(self): raise NotImplementedError class WrongNumberOfVars(CExtensionError): def __init__(self, location, exp_types, actual_types): CExtensionError.__init__(self, location) self.exp_types = exp_types self.actual_types = actual_types class NotEnoughVars(WrongNumberOfVars): def _get_desc(self): return 'Not enough arguments: expected %i (%s), but got %i (%s)' % ( len(self.exp_types), self.exp_types, len(self.actual_types), self.actual_types) class TooManyVars(WrongNumberOfVars): def _get_desc(self): return 'Too many arguments: expected %i (%s), but got %i (%s)' % ( len(self.exp_types), self.exp_types, len(self.actual_types), self.actual_types) class MismatchingType(CExtensionError): def __init__(self, location, arg_num, exp_type, actual_type): super(self.__class__, self).__init__(location) self.arg_num = arg_num self.exp_type = exp_type self.actual_type = actual_type def _get_desc(self): return 'Mismatching type of argument %i: expected "%s" but got "%s"' % ( self.arg_num, self.exp_type, self.actual_type) def validate_types(location, format_string, actual_types): try: exp_types = get_types(format_string) if len(actual_types) < len(exp_types): raise NotEnoughVars(location, actual_types, exp_types) if len(actual_types) > len(exp_types): raise TooManyVars(location, actual_types, exp_types) for i, (exp, actual) in enumerate(zip(exp_types, actual_types)): if exp != actual: raise MismatchingType(location, i+1, exp, actual) except CExtensionError, err: print err