def test_PythonStatement_flags_1(): block = PythonBlock("from __future__ import unicode_literals\nx\n", flags="division") s0, s1 = block.statements assert s0.block.source_flags == CompilerFlags("unicode_literals") assert s1.block.source_flags == CompilerFlags(0) assert s0.block.flags == CompilerFlags("unicode_literals", "division") assert s1.block.flags == CompilerFlags("unicode_literals", "division")
def flags(self): """ If this is a __future__ import, then the compiler_flag associated with it. Otherwise, 0. """ if self.split.module_name == "__future__": return CompilerFlags(self.split.member_name) else: return CompilerFlags(0)
def test_PythonBlock_flags_type_comment_1(): block = PythonBlock(dedent(''' a = 1 # type: int ''').lstrip()) if sys.version_info >= (3, 8): # Includes the type_comments flag assert block.flags == CompilerFlags(0x01000) else: assert block.flags == CompilerFlags(0x0000)
def test_PythonStatement_auto_flags_1(): block = PythonBlock( "from __future__ import unicode_literals\nprint(1,file=x)\n", flags="division", auto_flags=True) s0, s1 = block.statements assert s0.block.source_flags == CompilerFlags("unicode_literals") assert s1.block.source_flags == CompilerFlags(0) expected = CompilerFlags("unicode_literals", "division", "print_function") assert s0.block.flags == expected assert s1.block.flags == expected
def _parse_ast_nodes(text, flags, auto_flags, mode): """ Parse a block of lines into an AST. Also annotate ``input_flags``, ``source_flags``, and ``flags`` on the resulting ast node. :type text: ``FileText`` :type flags: ``CompilerFlags`` :type auto_flags: ``bool`` :param auto_flags: Whether to guess different flags if ``text`` can't be parsed with ``flags``. :param mode: Compilation mode: "exec", "single", or "eval". :rtype: ``ast.Module`` """ text = FileText(text) flags = CompilerFlags(flags) filename = str(text.filename) if text.filename else "<unknown>" source = text.joined source = dedent(source) if PY2 and isinstance(source, unicode): source = source.encode('utf-8') if not source.endswith("\n"): # Ensure that the last line ends with a newline (``ast`` barfs # otherwise). source += "\n" exp = None for flags in _flags_to_try(source, flags, auto_flags, mode): cflags = ast.PyCF_ONLY_AST | int(flags) try: result = compile(source, filename, mode, flags=cflags, dont_inherit=1) except SyntaxError as e: exp = e pass else: # Attach flags to the result. result.input_flags = flags result.source_flags = CompilerFlags.from_ast(result) result.flags = result.input_flags | result.source_flags result.text = text return result raise exp # SyntaxError
def test_PythonBlock_flags_type_comment_1(): block = PythonBlock(dedent(""" a = 1 # type: int """).lstrip()) if sys.version_info >= (3, 8): # Includes the type_comments flag with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) assert block.flags == CompilerFlags(0x01000) else: with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) assert block.flags == CompilerFlags(0x0000)
def _parse_ast_nodes(text, flags, auto_flags, mode): """ Parse a block of lines into an AST. Also annotate C{input_flags}, C{source_flags}, and C{flags} on the resulting ast node. @type text: C{FileText} @type flags: C{CompilerFlags} @type auto_flags: C{bool} @param auto_flags: Whether to guess different flags if C{text} can't be parsed with C{flags}. @param mode: Compilation mode: "exec", "single", or "eval". @rtype: C{ast.Module} """ text = FileText(text) flags = CompilerFlags(flags) filename = str(text.filename) if text.filename else "<unknown>" source = text.joined source = dedent(source) if not source.endswith("\n"): # Ensure that the last line ends with a newline (C{ast} barfs # otherwise). source += "\n" exp = None for flags in _flags_to_try(source, flags, auto_flags, mode): cflags = ast.PyCF_ONLY_AST | int(flags) try: result = compile(source, filename, mode, flags=cflags, dont_inherit=1) except SyntaxError as e: exp = e pass else: # Attach flags to the result. result.input_flags = flags result.source_flags = CompilerFlags.from_ast(result) result.flags = result.input_flags | result.source_flags result.text = text return result raise exp # SyntaxError
def test_PythonBlock_flags_deduce_1(): block = PythonBlock(dedent(''' from __future__ import print_function print("x", file=None) ''').lstrip()) assert block.flags == CompilerFlags(0x10000)
def from_text(cls, text, filename=None, startpos=None, flags=None, auto_flags=False): """ :type text: `FileText` or convertible :type filename: ``Filename`` :param filename: Filename, if not already given by ``text``. :type startpos: ``FilePos`` :param startpos: Starting position, if not already given by ``text``. :type flags: ``CompilerFlags`` :param flags: Input compiler flags. :param auto_flags: Whether to try other flags if ``flags`` fails. :rtype: `PythonBlock` """ text = FileText(text, filename=filename, startpos=startpos) self = object.__new__(cls) self.text = text self._input_flags = CompilerFlags(flags) self._auto_flags = auto_flags return self
def __new__(cls, arg, filename=None, startpos=None, flags=None, auto_flags=None): if isinstance(arg, PythonStatement): arg = arg.block # Fall through if isinstance(arg, cls): if filename is startpos is flags is None: return arg flags = CompilerFlags(flags, arg.flags) arg = arg.text # Fall through if isinstance(arg, (FileText, Filename, str, six.text_type)): return cls.from_text(arg, filename=filename, startpos=startpos, flags=flags, auto_flags=auto_flags) raise TypeError("%s: unexpected %s" % ( cls.__name__, type(arg).__name__, ))
def from_text(cls, text, filename=None, startpos=None, flags=None, auto_flags=False): """ @type text: L{FileText} or convertible @type filename: C{Filename} @param filename: Filename, if not already given by C{text}. @type startpos: C{FilePos} @param startpos: Starting position, if not already given by C{text}. @type flags: C{CompilerFlags} @param flags: Input compiler flags. @param auto_flags: Whether to try other flags if C{flags} fails. @rtype: L{PythonBlock} """ text = FileText(text, filename=filename, startpos=startpos) self = object.__new__(cls) self.text = text self._input_flags = CompilerFlags(flags) self._auto_flags = auto_flags return self
def test_PythonStatement_auto_flags_1(): block = PythonBlock( "from __future__ import unicode_literals\nprint(1,file=x)\n", flags="division", auto_flags=True) s0, s1 = block.statements assert s0.block.source_flags == CompilerFlags("unicode_literals") with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) assert s1.block.source_flags == CompilerFlags(0) if PY2: expected = CompilerFlags("unicode_literals", "division", "print_function") else: expected = CompilerFlags("unicode_literals", "division") assert s0.block.flags == expected assert s1.block.flags == expected
def flags(self): """ If this contains __future__ imports, then the bitwise-ORed of the compiler_flag values associated with the features. Otherwise, 0. """ imports = self._by_module_name[0].get("__future__", []) return CompilerFlags(*[imp.flags for imp in imports])
def test_CompilerFlags_eqne_1(): with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) assert CompilerFlags(0x18000) == CompilerFlags(0x18000) assert not (CompilerFlags(0x18000) != CompilerFlags(0x18000)) assert CompilerFlags(0x18000) != CompilerFlags.type_comments assert not (CompilerFlags(0x18000) == CompilerFlags(0x10000))
def test_CompilerFlags_compile_1(): # Should raise SyntaxError: with pytest.raises(SyntaxError): compile("print('x', file=None)", "?", "exec", flags=0, dont_inherit=1) # Shouldn't raise SyntaxError: compile("print('x', file=None)", "?", "exec", flags=CompilerFlags("print_function"), dont_inherit=1)
def _flags_to_try(source, flags, auto_flags, mode): """ Flags to try for ``auto_flags``. If ``auto_flags`` is False, then only yield ``flags``. If ``auto_flags`` is True, then yield ``flags`` and ``flags ^ print_function``. """ flags = CompilerFlags(flags) if not auto_flags: yield flags return if PY3: yield flags return if mode == "eval": if re.search(r"\bprint\b", source): flags = flags | CompilerFlags("print_function") yield flags return yield flags if re.search(r"\bprint\b", source): yield flags ^ CompilerFlags("print_function")
def _flags_to_try(source, flags, auto_flags, mode): """ Flags to try for C{auto_flags}. If C{auto_flags} is False, then only yield C{flags}. If C{auto_flags} is True, then yield C{flags} and C{flags ^ print_function}. """ flags = CompilerFlags(flags) if not auto_flags: yield flags return if sys.version_info[0] != 2: yield flags return if mode == "eval": if re.search(r"\bprint\b", source): flags = flags | CompilerFlags("print_function") yield flags return yield flags if re.search(r"\bprint\b", source): yield flags ^ CompilerFlags("print_function")
def ImportPathForRelativeImportsCtx(codeblock): """ Context manager that temporarily modifies C{sys.path} so that relative imports for the given C{codeblock} work as expected. @type codeblock: L{PythonBlock} """ codeblock = PythonBlock(codeblock) if not codeblock.filename: return NullCtx() if codeblock.flags & CompilerFlags("absolute_import"): return NullCtx() return ImportPathCtx(str(codeblock.filename.dir))
def __construct_from_annotated_ast(cls, annotated_ast_nodes, text, flags): # Constructor for internal use by _split_by_statement() or # concatenate(). ast_node = ast.Module(annotated_ast_nodes) ast_node.text = text ast_node.flags = flags if not hasattr(ast_node, "source_flags"): ast_node.source_flags = CompilerFlags.from_ast(annotated_ast_nodes) self = object.__new__(cls) self._ast_node_or_parse_exception = ast_node self.ast_node = ast_node self.annotated_ast_node = ast_node self.text = text self.flags = self._input_flags = flags self._auto_flags = False return self
def test_PythonStatement_flags_1(): block = PythonBlock("from __future__ import unicode_literals\nx\n", flags="division") s0, s1 = block.statements assert s0.block.source_flags == CompilerFlags("unicode_literals") with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) assert s1.block.source_flags == CompilerFlags(0) if sys.version_info >= (3, 8): assert s0.block.flags == CompilerFlags("unicode_literals", "division",) assert s1.block.flags == CompilerFlags("unicode_literals", "division",) else: assert s0.block.flags == CompilerFlags("unicode_literals", "division") assert s1.block.flags == CompilerFlags("unicode_literals", "division")
def test_PythonBlock_flags_1(): block = PythonBlock('print("x",\n file=None)\n', flags="print_function") assert block.flags == CompilerFlags(0x10000)
def test_CompilerFlags_from_names_single_1(): result = CompilerFlags("with_statement") assert result == CompilerFlags(0x8000)
def test_CompilerFlags_from_CompilerFlags_1(): result = CompilerFlags(CompilerFlags(0x10000), CompilerFlags(0x8000)) assert result == CompilerFlags(0x18000)
def test_CompilerFlags_from_mixed_multi_1(): result = CompilerFlags("print_function", 0x8000, CompilerFlags("division")) assert result == CompilerFlags(0x1a000)
def test_CompilerFlags_from_names_list_1(): result = CompilerFlags(["with_statement", "print_function"]) assert result == CompilerFlags(0x18000)
def test_CompilerFlags_from_ast_1(): node = ast.parse("from __future__ import with_statement, print_function") result = CompilerFlags(node) assert result == CompilerFlags(0x18000)
def test_CompilerFlags_bad_name_1(): with pytest.raises(ValueError): CompilerFlags("print_statement")
def test_CompilerFlags_bad_int_1(): with pytest.raises(ValueError): CompilerFlags(1)
import pytest import sys from textwrap import dedent import warnings from six import PY2, PY3 from pyflyby._file import FilePos, FileText, Filename from pyflyby._flags import CompilerFlags from pyflyby._parse import PythonBlock, PythonStatement from pyflyby._imports2s import SourceToSourceFileImportsTransformation if sys.version_info < (3, 8, 3): print_function_flag = CompilerFlags.from_int(0x10000) else: print_function_flag = CompilerFlags.from_int(0x100000) def test_PythonBlock_FileText_1(): text = FileText( dedent( """ foo() bar() """ ).lstrip(), filename="/foo/test_PythonBlock_1.py", startpos=(101, 55), )
def flags(self): """ If this is a __future__ import, then the bitwise-ORed of the compiler_flag values associated with the features. Otherwise, 0. """ return CompilerFlags(*[imp.flags for imp in self.imports])