Index: bindings/python/clang/cindex.py =================================================================== --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -73,6 +73,30 @@ # this by marshalling object arguments as void**. c_object_p = POINTER(c_void_p) +# Python 3 strings are unicode, translate them to/from utf8 for C-interop +if type(u"") == str: + class c_string_p(c_char_p): + def __init__(self, p=None): + if type(p) == str: + p = p.encode("utf8") + super(c_char_p, self).__init__(p) + + def __str__(self): + return str(self.value) + + @property + def value(self): + if super(c_char_p, self).value is None: + return None + return super(c_char_p, self).value.decode("utf8") + + @classmethod + def from_param(cls, param): + return cls(param) +else: + c_string_p = c_char_p + + callbacks = {} ### Exception Classes ### @@ -147,7 +171,7 @@ class _CXString(Structure): """Helper for transforming CXString results.""" - _fields_ = [("spelling", c_char_p), ("free", c_int)] + _fields_ = [("spelling", c_string_p), ("free", c_int)] def __del__(self): conf.lib.clang_disposeString(self) @@ -329,7 +353,7 @@ @property def spelling(self): - return conf.lib.clang_getDiagnosticSpelling(self) + return str(conf.lib.clang_getDiagnosticSpelling(self)) @property def ranges(self): @@ -358,8 +382,8 @@ def __getitem__(self, key): range = SourceRange() - value = conf.lib.clang_getDiagnosticFixIt(self.diag, key, - byref(range)) + value = str(conf.lib.clang_getDiagnosticFixIt(self.diag, key, + byref(range))) if len(value) == 0: raise IndexError @@ -392,12 +416,12 @@ @property def category_name(self): """The string name of the category for this diagnostic.""" - return conf.lib.clang_getDiagnosticCategoryText(self) + return str(conf.lib.clang_getDiagnosticCategoryText(self)) @property def option(self): """The command-line option that enables this diagnostic.""" - return conf.lib.clang_getDiagnosticOption(self, None) + return str(conf.lib.clang_getDiagnosticOption(self, None)) @property def disable_option(self): @@ -405,7 +429,7 @@ disable = _CXString() conf.lib.clang_getDiagnosticOption(self, byref(disable)) - return conf.lib.clang_getCString(disable) + return str(conf.lib.clang_getCString(disable)) def format(self, options=None): """ @@ -491,7 +515,7 @@ token_group = TokenGroup(tu, tokens_memory, tokens_count) - for i in xrange(0, count): + for i in range(0, count): token = Token() token.int_data = tokens_array[i].int_data token.ptr_data = tokens_array[i].ptr_data @@ -554,8 +578,8 @@ if value >= len(self.__class__._kinds): self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) if self.__class__._kinds[value] is not None: - raise ValueError,'{0} value {1} already loaded'.format( - str(self.__class__), value) + raise ValueError('{0} value {1} already loaded'.format( + str(self.__class__), value)) self.value = value self.__class__._kinds[value] = self self.__class__._name_map = None @@ -572,12 +596,12 @@ for key, value in self.__class__.__dict__.items(): if isinstance(value, self.__class__): self._name_map[value] = key - return self._name_map[self] + return str(self._name_map[self]) @classmethod def from_id(cls, id): if id >= len(cls._kinds) or cls._kinds[id] is None: - raise ValueError,'Unknown template argument kind %d' % id + raise ValueError('Unknown template argument kind %d' % id) return cls._kinds[id] def __repr__(self): @@ -596,7 +620,7 @@ @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" - return filter(None, CursorKind._kinds) + return [x for x in CursorKind._kinds if x] def is_declaration(self): """Test if this is a declaration kind.""" @@ -1427,9 +1451,9 @@ def spelling(self): """Return the spelling of the entity pointed at by the cursor.""" if not hasattr(self, '_spelling'): - self._spelling = conf.lib.clang_getCursorSpelling(self) + self._spelling = str(conf.lib.clang_getCursorSpelling(self)) - return self._spelling + return str(self._spelling) @property def displayname(self): @@ -1441,7 +1465,7 @@ arguments of a class template specialization. """ if not hasattr(self, '_displayname'): - self._displayname = conf.lib.clang_getCursorDisplayName(self) + self._displayname = str(conf.lib.clang_getCursorDisplayName(self)) return self._displayname @@ -1449,7 +1473,7 @@ def mangled_name(self): """Return the mangled name for the entity referenced by this cursor.""" if not hasattr(self, '_mangled_name'): - self._mangled_name = conf.lib.clang_Cursor_getMangling(self) + self._mangled_name = str(conf.lib.clang_Cursor_getMangling(self)) return self._mangled_name @@ -1588,7 +1612,7 @@ self._objc_type_encoding = \ conf.lib.clang_getDeclObjCTypeEncoding(self) - return self._objc_type_encoding + return str(self._objc_type_encoding) @property def hash(self): @@ -1635,12 +1659,18 @@ @property def brief_comment(self): """Returns the brief comment text associated with that Cursor""" - return conf.lib.clang_Cursor_getBriefCommentText(self) + r = conf.lib.clang_Cursor_getBriefCommentText(self) + if not r: + return None + return str(r) @property def raw_comment(self): """Returns the raw comment text associated with that Cursor""" - return conf.lib.clang_Cursor_getRawCommentText(self) + r = conf.lib.clang_Cursor_getRawCommentText(self) + if not r: + return None + return str(r) def get_arguments(self): """Return an iterator for accessing the arguments of this cursor.""" @@ -1775,7 +1805,7 @@ if value >= len(StorageClass._kinds): StorageClass._kinds += [None] * (value - len(StorageClass._kinds) + 1) if StorageClass._kinds[value] is not None: - raise ValueError,'StorageClass already loaded' + raise ValueError('StorageClass already loaded') self.value = value StorageClass._kinds[value] = self StorageClass._name_map = None @@ -1796,7 +1826,7 @@ @staticmethod def from_id(id): if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: - raise ValueError,'Unknown storage class %d' % id + raise ValueError('Unknown storage class %d' % id) return StorageClass._kinds[id] def __repr__(self): @@ -1849,7 +1879,7 @@ @property def spelling(self): """Retrieve the spelling of this TypeKind.""" - return conf.lib.clang_getTypeKindSpelling(self.value) + return str(conf.lib.clang_getTypeKindSpelling(self.value)) def __repr__(self): return 'TypeKind.%s' % (self.name,) @@ -2125,7 +2155,7 @@ """ Retrieve the offset of a field in the record. """ - return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname)) + return conf.lib.clang_Type_getOffsetOf(self, fieldname) def get_ref_qualifier(self): """ @@ -2152,7 +2182,7 @@ @property def spelling(self): """Retrieve the spelling of this Type.""" - return conf.lib.clang_getTypeSpelling(self) + return str(conf.lib.clang_getTypeSpelling(self)) def __eq__(self, other): if type(other) != type(self): @@ -2184,7 +2214,7 @@ class _CXUnsavedFile(Structure): """Helper for passing unsaved file arguments.""" - _fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)] + _fields_ = [("name", c_string_p), ("contents", c_string_p), ('length', c_ulong)] # Functions calls through the python interface are rather slow. Fortunately, # for most symboles, we do not need to perform a function call. Their spelling @@ -2230,7 +2260,7 @@ self.__kindNumberCache = -1 def __repr__(self): - return "{'" + self.spelling + "', " + str(self.kind) + "}" + return "{'" + str(self.spelling) + "', " + str(self.kind) + "}" @CachedProperty def spelling(self): @@ -2338,6 +2368,7 @@ return conf.lib.clang_getCompletionBriefComment(self.obj) return _CXString() + def __repr__(self): return " | ".join([str(a) for a in self]) \ + " || Priority: " + str(self.priority) \ @@ -2539,7 +2570,9 @@ args_array = None if len(args) > 0: - args_array = (c_char_p * len(args))(* args) + args_array = (c_string_p * len(args))() + for i,a in enumerate(args): + args_array[i] = c_string_p(a) unsaved_array = None if len(unsaved_files) > 0: @@ -2548,8 +2581,8 @@ if hasattr(contents, "read"): contents = contents.read() - unsaved_array[i].name = name - unsaved_array[i].contents = contents + unsaved_array[i].name = c_string_p(name) + unsaved_array[i].contents = c_string_p(contents) unsaved_array[i].length = len(contents) ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array, @@ -2604,7 +2637,7 @@ @property def spelling(self): """Get the original translation unit source file name.""" - return conf.lib.clang_getTranslationUnitSpelling(self) + return str(conf.lib.clang_getTranslationUnitSpelling(self)) def get_includes(self): """ @@ -2727,9 +2760,9 @@ # FIXME: It would be great to support an efficient version # of this, one day. value = value.read() - print value + print(value) if not isinstance(value, str): - raise TypeError,'Unexpected unsaved file contents.' + raise TypeError('Unexpected unsaved file contents.') unsaved_files_array[i].name = name unsaved_files_array[i].contents = value unsaved_files_array[i].length = len(value) @@ -2791,11 +2824,11 @@ # FIXME: It would be great to support an efficient version # of this, one day. value = value.read() - print value + print(value) if not isinstance(value, str): - raise TypeError,'Unexpected unsaved file contents.' - unsaved_files_array[i].name = name - unsaved_files_array[i].contents = value + raise TypeError('Unexpected unsaved file contents.') + unsaved_files_array[i].name = c_string_p(name) + unsaved_files_array[i].contents = c_string_p(value) unsaved_files_array[i].length = len(value) ptr = conf.lib.clang_codeCompleteAt(self, path, line, column, unsaved_files_array, len(unsaved_files), options) @@ -2830,7 +2863,7 @@ @property def name(self): """Return the complete file and path name of the file.""" - return conf.lib.clang_getCString(conf.lib.clang_getFileName(self)) + return str(conf.lib.clang_getCString(conf.lib.clang_getFileName(self))) @property def time(self): @@ -2838,7 +2871,7 @@ return conf.lib.clang_getFileTime(self) def __str__(self): - return self.name + return str(self.name) def __repr__(self): return "" % (self.name) @@ -2907,12 +2940,12 @@ @property def directory(self): """Get the working directory for this CompileCommand""" - return conf.lib.clang_CompileCommand_getDirectory(self.cmd) + return str(conf.lib.clang_CompileCommand_getDirectory(self.cmd)) @property def filename(self): """Get the working filename for this CompileCommand""" - return conf.lib.clang_CompileCommand_getFilename(self.cmd) + return str(conf.lib.clang_CompileCommand_getFilename(self.cmd)) @property def arguments(self): @@ -2923,8 +2956,8 @@ Invariant : the first argument is the compiler executable """ length = conf.lib.clang_CompileCommand_getNumArgs(self.cmd) - for i in xrange(length): - yield conf.lib.clang_CompileCommand_getArg(self.cmd, i) + for i in range(length): + yield str(conf.lib.clang_CompileCommand_getArg(self.cmd, i)) class CompileCommands(object): """ @@ -3018,7 +3051,7 @@ This is the textual representation of the token in source. """ - return conf.lib.clang_getTokenSpelling(self._tu, self) + return str(conf.lib.clang_getTokenSpelling(self._tu, self)) @property def kind(self): @@ -3061,7 +3094,7 @@ [c_object_p]), ("clang_CompilationDatabase_fromDirectory", - [c_char_p, POINTER(c_uint)], + [c_string_p, POINTER(c_uint)], c_object_p, CompilationDatabase.from_result), @@ -3071,7 +3104,7 @@ CompileCommands.from_result), ("clang_CompilationDatabase_getCompileCommands", - [c_object_p, c_char_p], + [c_object_p, c_string_p], c_object_p, CompileCommands.from_result), @@ -3106,7 +3139,7 @@ c_uint), ("clang_codeCompleteAt", - [TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int], + [TranslationUnit, c_string_p, c_int, c_int, c_void_p, c_int, c_int], POINTER(CCRStructure)), ("clang_codeCompleteGetDiagnostic", @@ -3122,7 +3155,7 @@ c_object_p), ("clang_createTranslationUnit", - [Index, c_char_p], + [Index, c_string_p], c_object_p), ("clang_CXXConstructor_isConvertingConstructor", @@ -3272,7 +3305,7 @@ ("clang_getCString", [_CXString], - c_char_p), + c_string_p), ("clang_getCursor", [TranslationUnit, SourceLocation], @@ -3419,7 +3452,7 @@ Type.from_result), ("clang_getFile", - [TranslationUnit, c_char_p], + [TranslationUnit, c_string_p], c_object_p), ("clang_getFileName", @@ -3548,7 +3581,7 @@ ("clang_getTUResourceUsageName", [c_uint], - c_char_p), + c_string_p), ("clang_getTypeDeclaration", [Type], @@ -3643,7 +3676,7 @@ bool), ("clang_parseTranslationUnit", - [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int], + [Index, c_string_p, c_void_p, c_int, c_void_p, c_int, c_int], c_object_p), ("clang_reparseTranslationUnit", @@ -3651,7 +3684,7 @@ c_int), ("clang_saveTranslationUnit", - [TranslationUnit, c_char_p, c_uint], + [TranslationUnit, c_string_p, c_uint], c_int), ("clang_tokenize", @@ -3723,7 +3756,7 @@ Type.from_result), ("clang_Type_getOffsetOf", - [Type, c_char_p], + [Type, c_string_p], c_longlong), ("clang_Type_getSizeOf", @@ -3782,7 +3815,8 @@ def register(item): return register_function(lib, item, ignore_errors) - map(register, functionList) + for f in functionList: + register(f) class Config: library_path = None Index: bindings/python/tests/cindex/test_comment.py =================================================================== --- bindings/python/tests/cindex/test_comment.py +++ bindings/python/tests/cindex/test_comment.py @@ -34,6 +34,12 @@ f = get_cursor(tu, 'f') raw = f.raw_comment brief = f.brief_comment + + print(raw) + print(type(raw)) + print(brief) + print(type(brief)) + assert raw is None assert brief is None Index: bindings/python/tests/cindex/test_translation_unit.py =================================================================== --- bindings/python/tests/cindex/test_translation_unit.py +++ bindings/python/tests/cindex/test_translation_unit.py @@ -59,9 +59,13 @@ assert spellings[-1] == 'y' def test_unsaved_files_2(): - import StringIO + try: + from StringIO import StringIO + except: + from io import StringIO + tu = TranslationUnit.from_source('fake.c', unsaved_files = [ - ('fake.c', StringIO.StringIO('int x;'))]) + ('fake.c', StringIO('int x;'))]) spellings = [c.spelling for c in tu.cursor.get_children()] assert spellings[-1] == 'x'