[libclang/python] Bump minimum compatibility to Python 3.6 (#77228)

Remove Python 2 support and clean up code that conditions based on
version.

Issue #76664.
This commit is contained in:
Craig Hesling 2024-01-17 01:02:54 -08:00 committed by GitHub
parent 34b106789a
commit 75f232181a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 74 additions and 99 deletions

View File

@ -10,7 +10,7 @@ runner. For example:
--
$ env PYTHONPATH=$(echo ~/llvm/clang/bindings/python/) \
CLANG_LIBRARY_PATH=$(llvm-config --libdir) \
python -m unittest discover -v
python3 -m unittest discover -v
tests.cindex.test_index.test_create ... ok
...

View File

@ -66,81 +66,50 @@ from ctypes import *
import clang.enumerations
import collections.abc
import os
import sys
if sys.version_info[0] == 3:
# Python 3 strings are unicode, translate them to/from utf8 for C-interop.
class c_interop_string(c_char_p):
def __init__(self, p=None):
if p is None:
p = ""
if isinstance(p, str):
p = p.encode("utf8")
super(c_char_p, self).__init__(p)
def __str__(self):
return self.value
# Python 3 strings are unicode, translate them to/from utf8 for C-interop.
class c_interop_string(c_char_p):
def __init__(self, p=None):
if p is None:
p = ""
if isinstance(p, str):
p = p.encode("utf8")
super(c_char_p, self).__init__(p)
@property
def value(self):
if super(c_char_p, self).value is None:
return None
return super(c_char_p, self).value.decode("utf8")
def __str__(self):
return self.value
@classmethod
def from_param(cls, param):
if isinstance(param, str):
return cls(param)
if isinstance(param, bytes):
return cls(param)
if param is None:
# Support passing null to C functions expecting char arrays
return None
raise TypeError(
"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__)
)
@property
def value(self):
if super(c_char_p, self).value is None:
return None
return super(c_char_p, self).value.decode("utf8")
@staticmethod
def to_python_string(x, *args):
return x.value
@classmethod
def from_param(cls, param):
if isinstance(param, str):
return cls(param)
if isinstance(param, bytes):
return cls(param)
if param is None:
# Support passing null to C functions expecting char arrays
return None
raise TypeError(
"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__)
)
def b(x):
if isinstance(x, bytes):
return x
return x.encode("utf8")
@staticmethod
def to_python_string(x, *args):
return x.value
elif sys.version_info[0] == 2:
# Python 2 strings are utf8 byte strings, no translation is needed for
# C-interop.
c_interop_string = c_char_p
def _to_python_string(x, *args):
return x
c_interop_string.to_python_string = staticmethod(_to_python_string)
def b(x):
return x
# Importing ABC-s directly from collections is deprecated since Python 3.7,
# will stop working in Python 3.8.
# See: https://docs.python.org/dev/whatsnew/3.7.html#id3
if sys.version_info[:2] >= (3, 7):
from collections import abc as collections_abc
else:
import collections as collections_abc
# We only support PathLike objects on Python version with os.fspath present
# to be consistent with the Python standard library. On older Python versions
# we only support strings and we have dummy fspath to just pass them through.
try:
fspath = os.fspath
except AttributeError:
def fspath(x):
def b(x):
if isinstance(x, bytes):
return x
return x.encode("utf8")
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
@ -202,7 +171,7 @@ class TranslationUnitSaveError(Exception):
### Structures and Utility Classes ###
class CachedProperty(object):
class CachedProperty:
"""Decorator that lazy-loads the value of a property.
The first time the property is accessed, the original property function is
@ -392,7 +361,7 @@ class SourceRange(Structure):
return "<SourceRange start %r, end %r>" % (self.start, self.end)
class Diagnostic(object):
class Diagnostic:
"""
A Diagnostic is a single instance of a Clang diagnostic. It includes the
diagnostic severity, the message, the location the diagnostic occurred, as
@ -433,7 +402,7 @@ class Diagnostic(object):
@property
def ranges(self):
class RangeIterator(object):
class RangeIterator:
def __init__(self, diag):
self.diag = diag
@ -449,7 +418,7 @@ class Diagnostic(object):
@property
def fixits(self):
class FixItIterator(object):
class FixItIterator:
def __init__(self, diag):
self.diag = diag
@ -468,7 +437,7 @@ class Diagnostic(object):
@property
def children(self):
class ChildDiagnosticsIterator(object):
class ChildDiagnosticsIterator:
def __init__(self, diag):
self.diag_set = conf.lib.clang_getChildDiagnostics(diag)
@ -532,7 +501,7 @@ class Diagnostic(object):
return self.ptr
class FixIt(object):
class FixIt:
"""
A FixIt represents a transformation to be applied to the source to
"fix-it". The fix-it should be applied by replacing the given source range
@ -547,7 +516,7 @@ class FixIt(object):
return "<FixIt range %r, value %r>" % (self.range, self.value)
class TokenGroup(object):
class TokenGroup:
"""Helper class to facilitate token management.
Tokens are allocated from libclang in chunks. They must be disposed of as a
@ -603,7 +572,7 @@ class TokenGroup(object):
yield token
class TokenKind(object):
class TokenKind:
"""Describes a specific type of a Token."""
_value_map = {} # int -> TokenKind
@ -642,7 +611,7 @@ class TokenKind(object):
### Cursor Kinds ###
class BaseEnumeration(object):
class BaseEnumeration:
"""
Common base class for named enumerations held in sync with Index.h values.
@ -2059,7 +2028,7 @@ class Cursor(Structure):
return res
class StorageClass(object):
class StorageClass:
"""
Describes the storage class of a declaration
"""
@ -2353,7 +2322,7 @@ class Type(Structure):
container is a Type instance.
"""
class ArgumentsIterator(collections_abc.Sequence):
class ArgumentsIterator(collections.abc.Sequence):
def __init__(self, parent):
self.parent = parent
self.length = None
@ -2608,7 +2577,7 @@ class Type(Structure):
# a void*.
class ClangObject(object):
class ClangObject:
"""
A helper for Clang objects. This class helps act as an intermediary for
the ctypes library and the Clang CIndex library.
@ -2656,8 +2625,8 @@ SpellingCache = {
}
class CompletionChunk(object):
class Kind(object):
class CompletionChunk:
class Kind:
def __init__(self, name):
self.name = name
@ -2747,7 +2716,7 @@ completionChunkKindMap = {
class CompletionString(ClangObject):
class Availability(object):
class Availability:
def __init__(self, name):
self.name = name
@ -2849,7 +2818,7 @@ class CodeCompletionResults(ClangObject):
@property
def diagnostics(self):
class DiagnosticsItr(object):
class DiagnosticsItr:
def __init__(self, ccr):
self.ccr = ccr
@ -3003,13 +2972,13 @@ class TranslationUnit(ClangObject):
if hasattr(contents, "read"):
contents = contents.read()
contents = b(contents)
unsaved_array[i].name = b(fspath(name))
unsaved_array[i].name = b(os.fspath(name))
unsaved_array[i].contents = contents
unsaved_array[i].length = len(contents)
ptr = conf.lib.clang_parseTranslationUnit(
index,
fspath(filename) if filename is not None else None,
os.fspath(filename) if filename is not None else None,
args_array,
len(args),
unsaved_array,
@ -3040,7 +3009,7 @@ class TranslationUnit(ClangObject):
if index is None:
index = Index.create()
ptr = conf.lib.clang_createTranslationUnit(index, fspath(filename))
ptr = conf.lib.clang_createTranslationUnit(index, os.fspath(filename))
if not ptr:
raise TranslationUnitLoadError(filename)
@ -3159,7 +3128,7 @@ class TranslationUnit(ClangObject):
Return an iterable (and indexable) object containing the diagnostics.
"""
class DiagIterator(object):
class DiagIterator:
def __init__(self, tu):
self.tu = tu
@ -3193,7 +3162,7 @@ class TranslationUnit(ClangObject):
if hasattr(contents, "read"):
contents = contents.read()
contents = b(contents)
unsaved_files_array[i].name = b(fspath(name))
unsaved_files_array[i].name = b(os.fspath(name))
unsaved_files_array[i].contents = contents
unsaved_files_array[i].length = len(contents)
ptr = conf.lib.clang_reparseTranslationUnit(
@ -3217,7 +3186,11 @@ class TranslationUnit(ClangObject):
"""
options = conf.lib.clang_defaultSaveOptions(self)
result = int(
conf.lib.clang_saveTranslationUnit(self, fspath(filename), options)
conf.lib.clang_saveTranslationUnit(
self,
os.fspath(filename),
options,
)
)
if result != 0:
raise TranslationUnitSaveError(result, "Error saving TranslationUnit.")
@ -3261,12 +3234,12 @@ class TranslationUnit(ClangObject):
if hasattr(contents, "read"):
contents = contents.read()
contents = b(contents)
unsaved_files_array[i].name = b(fspath(name))
unsaved_files_array[i].name = b(os.fspath(name))
unsaved_files_array[i].contents = contents
unsaved_files_array[i].length = len(contents)
ptr = conf.lib.clang_codeCompleteAt(
self,
fspath(path),
os.fspath(path),
line,
column,
unsaved_files_array,
@ -3300,7 +3273,9 @@ class File(ClangObject):
@staticmethod
def from_name(translation_unit, file_name):
"""Retrieve a file handle within the given translation unit."""
return File(conf.lib.clang_getFile(translation_unit, fspath(file_name)))
return File(
conf.lib.clang_getFile(translation_unit, os.fspath(file_name)),
)
@property
def name(self):
@ -3328,7 +3303,7 @@ class File(ClangObject):
return res
class FileInclusion(object):
class FileInclusion:
"""
The FileInclusion class represents the inclusion of one source file by
another via a '#include' directive or as the input file for the translation
@ -3377,7 +3352,7 @@ class CompilationDatabaseError(Exception):
Exception.__init__(self, "Error %d: %s" % (enumeration, message))
class CompileCommand(object):
class CompileCommand:
"""Represents the compile command used to build a file"""
def __init__(self, cmd, ccmds):
@ -3409,7 +3384,7 @@ class CompileCommand(object):
yield conf.lib.clang_CompileCommand_getArg(self.cmd, i)
class CompileCommands(object):
class CompileCommands:
"""
CompileCommands is an iterable object containing all CompileCommand
that can be used for building a specific file.
@ -3460,7 +3435,7 @@ class CompilationDatabase(ClangObject):
errorCode = c_uint()
try:
cdb = conf.lib.clang_CompilationDatabase_fromDirectory(
fspath(buildDir), byref(errorCode)
os.fspath(buildDir), byref(errorCode)
)
except CompilationDatabaseError as e:
raise CompilationDatabaseError(
@ -3474,7 +3449,7 @@ class CompilationDatabase(ClangObject):
build filename. Returns None if filename is not found in the database.
"""
return conf.lib.clang_CompilationDatabase_getCompileCommands(
self, fspath(filename)
self, os.fspath(filename)
)
def getAllCompileCommands(self):
@ -3865,7 +3840,7 @@ def register_functions(lib, ignore_errors):
register(f)
class Config(object):
class Config:
library_path = None
library_file = None
compatibility_check = True
@ -3880,7 +3855,7 @@ class Config(object):
"any other functionalities in libclang."
)
Config.library_path = fspath(path)
Config.library_path = os.fspath(path)
@staticmethod
def set_library_file(filename):
@ -3891,7 +3866,7 @@ class Config(object):
"any other functionalities in libclang."
)
Config.library_file = fspath(filename)
Config.library_file = os.fspath(filename)
@staticmethod
def set_compatibility_check(check_status):