This commit is contained in:
Waylon Walker 2022-03-31 20:20:07 -05:00
commit 38355d2442
No known key found for this signature in database
GPG key ID: 66E2BF2B4190EFE4
9083 changed files with 1225834 additions and 0 deletions

View file

@ -0,0 +1,236 @@
# pyflyby/_flags.py.
# Copyright (C) 2011, 2012, 2013, 2014 Karl Chen.
# License: MIT http://opensource.org/licenses/MIT
from __future__ import (absolute_import, division, print_function,
with_statement)
import __future__
import ast
import operator
import six
from six.moves import reduce
import warnings
from pyflyby._util import cached_attribute
# Initialize mappings from compiler_flag to feature name and vice versa.
_FLAG2NAME = {}
_NAME2FLAG = {}
for name in __future__.all_feature_names:
flag = getattr(__future__, name).compiler_flag
_FLAG2NAME[flag] = name
_NAME2FLAG[name] = flag
for name in dir(ast):
if name.startswith('PyCF'):
flag_name = name[len('PyCF_'):].lower()
flag = getattr(ast, name)
_FLAG2NAME[flag] = flag_name
_NAME2FLAG[flag_name] = flag
_FLAGNAME_ITEMS = sorted(_FLAG2NAME.items())
_ALL_FLAGS = reduce(operator.or_, _FLAG2NAME.keys())
class CompilerFlags(int):
"""
Representation of Python "compiler flags", i.e. features from __future__.
>>> print(CompilerFlags(0x18000).__interactive_display__()) # doctest: +SKIP
CompilerFlags(0x18000) # from __future__ import with_statement, print_function
>>> print(CompilerFlags(0x10000, 0x8000).__interactive_display__()) # doctest: +SKIP
CompilerFlags(0x18000) # from __future__ import with_statement, print_function
>>> print(CompilerFlags('with_statement', 'print_function').__interactive_display__()) # doctest: +SKIP
CompilerFlags(0x18000) # from __future__ import with_statement, print_function
This can be used as an argument to the built-in compile() function. For
instance, in Python 2::
>>> compile("print('x', file=None)", "?", "exec", flags=0, dont_inherit=1) #doctest:+SKIP
Traceback (most recent call last):
...
SyntaxError: invalid syntax
>>> compile("print('x', file=None)", "?", "exec", flags=CompilerFlags("print_function"), dont_inherit=1) #doctest:+ELLIPSIS
<code object ...>
"""
def __new__(cls, *args):
"""
Construct a new ``CompilerFlags`` instance.
:param args:
Any number (zero or more) ``CompilerFlags`` s, ``int`` s, or ``str`` s,
which are bitwise-ORed together.
:rtype:
`CompilerFlags`
"""
if len(args) == 0:
return cls._ZERO
elif len(args) == 1:
arg, = args
if isinstance(arg, cls):
return arg
elif arg is None:
return cls._ZERO
elif isinstance(arg, int):
warnings.warn('creating CompilerFlags from integers is deprecated, '
' flags values change between Python versions. If you are sure use .from_int',
DeprecationWarning, stacklevel=2)
return cls.from_int(arg)
elif isinstance(arg, six.string_types):
return cls.from_str(arg)
elif isinstance(arg, ast.AST):
return cls.from_ast(arg)
elif isinstance(arg, (tuple, list)):
return cls(*arg)
else:
raise TypeError("CompilerFlags: unknown type %s"
% (type(arg).__name__,))
else:
flags = []
for x in args:
if isinstance(x, cls):
flags.append(int(x))
elif isinstance(x, int):
warnings.warn(
"creating CompilerFlags from integers is deprecated, "
" flags values change between Python versions. If you are sure use .from_int",
DeprecationWarning,
stacklevel=2,
)
flags.append(x)
elif isinstance(x, str):
flags.append(int(cls(x)))
else:
raise ValueError
#assert flags == [0x10000, 0x8000], flags
return cls.from_int(reduce(operator.or_, flags))
@classmethod
def from_int(cls, arg):
if arg == -1:
return cls._UNKNOWN # Instance optimization
if arg == 0:
return cls._ZERO # Instance optimization
self = int.__new__(cls, arg)
bad_flags = int(self) & ~_ALL_FLAGS
if bad_flags:
raise ValueError(
"CompilerFlags: unknown flag value(s) %s %s" % (bin(bad_flags), hex(bad_flags)))
return self
@classmethod
def from_str(cls, arg):
try:
flag = _NAME2FLAG[arg]
except KeyError:
raise ValueError(
"CompilerFlags: unknown flag %r" % (arg,))
return cls.from_int(flag)
@classmethod
def from_ast(cls, nodes):
"""
Parse the compiler flags from AST node(s).
:type nodes:
``ast.AST`` or sequence thereof
:rtype:
``CompilerFlags``
"""
if isinstance(nodes, ast.Module):
nodes = nodes.body
elif isinstance(nodes, ast.AST):
nodes = [nodes]
flags = []
for node in nodes:
if not isinstance(node, ast.ImportFrom):
# Got a non-import; stop looking further.
break
if not node.module == "__future__":
# Got a non-__future__-import; stop looking further.
break
# Get the feature names.
names = [n.name for n in node.names]
flags.extend(names)
return cls(flags)
@cached_attribute
def names(self):
return tuple(
n
for f, n in _FLAGNAME_ITEMS
if f & self)
def __or__(self, o):
if o == 0:
return self
if not isinstance(o, CompilerFlags):
o = CompilerFlags(o)
if self == 0:
return o
return CompilerFlags.from_int(int(self) | int(o))
def __ror__(self, o):
return self | o
def __and__(self, o):
if not isinstance(o, int):
o = CompilerFlags(o)
return CompilerFlags.from_int(int(self) & int(o))
def __rand__(self, o):
return self & o
def __xor__(self, o):
if not isinstance(o, CompilerFlags):
o = CompilerFlags.from_int(o)
return CompilerFlags.from_int(int(self) ^ int(o))
def __rxor__(self, o):
return self ^ o
def __repr__(self):
return "CompilerFlags(%s)" % (hex(self),)
def __str__(self):
return hex(self)
def __interactive_display__(self):
s = repr(self)
if self != 0:
s += " # from __future__ import " + ", ".join(self.names)
return s
CompilerFlags._ZERO = int.__new__(CompilerFlags, 0)
CompilerFlags._UNKNOWN = int.__new__(CompilerFlags, -1)
# flags that _may_ exists on future versions.
_future_flags = {
"nested_scopes",
"generators",
"division",
"absolute_import",
"with_statement",
"print_function",
"unicode_literals",
"barry_as_FLUFL",
"generator_stop",
"annotations",
"allow_top_level_await",
"only_ast",
"type_comments",
}
for k in _future_flags:
setattr(CompilerFlags, k, CompilerFlags._UNKNOWN)
for k, v in _NAME2FLAG.items():
setattr(CompilerFlags, k, CompilerFlags.from_int(v))