# -*- coding: utf-8 -*-
"""
This module contains snippets of Python 3 code (invalid Python 2) and
tests for whether they can be passed to ``pasteurize`` and
immediately run under both Python 2 and Python 3.
"""

from __future__ import print_function, absolute_import

import pprint
from subprocess import Popen, PIPE
import tempfile
import os

from future.tests.base import CodeHandler, unittest, skip26


class TestPasteurize(CodeHandler):
    """
    After running ``pasteurize``, these Python 3 code snippets should run
    on both Py3 and Py2.
    """

    def setUp(self):
        # For tests that need a text file:
        _, self.textfilename = tempfile.mkstemp(text=True)
        super(TestPasteurize, self).setUp()

    def tearDown(self):
        os.unlink(self.textfilename)

    @skip26    # Python 2.6's lib2to3 causes the "from builtins import
               # range" line to be stuck at the bottom of the module!
    def test_range_slice(self):
        """
        After running ``pasteurize``, this Python 3 code should run
        quickly on both Py3 and Py2 without a MemoryError
        """
        code = '''
        for i in range(10**8)[:10]:
            pass
        '''
        self.unchanged(code, from3=True)

    def test_print(self):
        """
        This Python 3-only code is a SyntaxError on Py2 without the
        print_function import from __future__.
        """
        code = '''
        import sys
        print('Hello', file=sys.stderr)
        '''
        self.unchanged(code, from3=True)

    def test_division(self):
        """
        True division should not be screwed up by conversion from 3 to both
        """
        code = '''
        x = 3 / 2
        assert x == 1.5
        '''
        self.unchanged(code, from3=True)

    # TODO: write / fix the raise_ fixer so that it uses the raise_ function
    @unittest.expectedFailure
    def test_exception_indentation(self):
        """
        As of v0.11.2, pasteurize broke the indentation of ``raise`` statements
        using with_traceback. Test for this.
        """
        before = '''
        import sys
        if True:
            try:
                'string' + 1
            except TypeError:
                ty, va, tb = sys.exc_info()
                raise TypeError("can't do that!").with_traceback(tb)
        '''
        after = '''
        import sys
        from future.utils import raise_with_traceback
        if True:
            try:
                'string' + 1
            except TypeError:
                ty, va, tb = sys.exc_info()
                raise_with_traceback(TypeError("can't do that!"), tb)
        '''
        self.convert_check(before, after, from3=True)

    # TODO: fix and test this test
    @unittest.expectedFailure
    def test_urllib_request(self):
        """
        Example Python 3 code using the new urllib.request module.

        Does the ``pasteurize`` script handle this?
        """
        before = """
            import pprint
            import urllib.request

            URL = 'http://pypi.python.org/pypi/{}/json'
            package = 'future'

            r = urllib.request.urlopen(URL.format(package))
            pprint.pprint(r.read())
        """
        after = """
            import pprint
            import future.standard_library.urllib.request as urllib_request

            URL = 'http://pypi.python.org/pypi/{}/json'
            package = 'future'

            r = urllib_request.urlopen(URL.format(package))
            pprint.pprint(r.read())
        """

        self.convert_check(before, after, from3=True)

    def test_urllib_refactor2(self):
        before = """
        import urllib.request, urllib.parse

        f = urllib.request.urlopen(url, timeout=15)
        filename = urllib.parse.urlparse(url)[2].split('/')[-1]
        """

        after = """
        from future.standard_library.urllib import request as urllib_request
        from future.standard_library.urllib import parse as urllib_parse

        f = urllib_request.urlopen(url, timeout=15)
        filename = urllib_parse.urlparse(url)[2].split('/')[-1]
        """

    def test_correct_exit_status(self):
        """
        Issue #119: futurize and pasteurize were not exiting with the correct
        status code. This is because the status code returned from
        libfuturize.main.main() etc. was a ``newint``, which sys.exit() always
        translates into 1!
        """
        from libpasteurize.main import main
        # Try pasteurizing this test script:
        retcode = main([self.textfilename])
        self.assertTrue(isinstance(retcode, int))   # i.e. Py2 builtin int


class TestFuturizeAnnotations(CodeHandler):
    @unittest.expectedFailure
    def test_return_annotations_alone(self):
        before = "def foo() -> 'bar': pass"
        after = """
        def foo(): pass
        foo.__annotations__ = {'return': 'bar'}
        """
        self.convert_check(before, after, from3=True)

        b = """
        def foo() -> "bar":
            print "baz"
            print "what's next, again?"
        """
        a = """
        def foo():
            print "baz"
            print "what's next, again?"
        """
        self.convert_check(b, a, from3=True)

    @unittest.expectedFailure
    def test_single_param_annotations(self):
        b = "def foo(bar:'baz'): pass"
        a = """
        def foo(bar): pass
        foo.__annotations__ = {'bar': 'baz'}
        """
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"baz"="spam"):
            print("what's next, again?")
            print("whatever.")
        """
        a = """
        def foo(bar="spam"):
            print("what's next, again?")
            print("whatever.")
        foo.__annotations__ = {'bar': 'baz'}
        """
        self.convert_check(b, a, from3=True)

    def test_multiple_param_annotations(self):
        b = "def foo(bar:'spam'=False, baz:'eggs'=True, ham:False='spaghetti'): pass"
        a = "def foo(bar=False, baz=True, ham='spaghetti'): pass"
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"spam"=False, baz:"eggs"=True, ham:False="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        a = """
        def foo(bar=False, baz=True, ham="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        self.convert_check(b, a, from3=True)

    def test_mixed_annotations(self):
        b = "def foo(bar=False, baz:'eggs'=True, ham:False='spaghetti') -> 'zombies': pass"
        a = "def foo(bar=False, baz=True, ham='spaghetti'): pass"
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"spam"=False, baz=True, ham:False="spam") -> 'air':
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        a = """
        def foo(bar=False, baz=True, ham="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        self.convert_check(b, a, from3=True)

        b = "def foo(bar) -> 'brains': pass"
        a = "def foo(bar): pass"
        self.convert_check(b, a, from3=True)

    def test_functions_unchanged(self):
        s = "def foo(): pass"
        self.unchanged(s, from3=True)

        s = """
        def foo():
            pass
            pass
        """
        self.unchanged(s, from3=True)

        s = """
        def foo(bar='baz'):
            pass
            pass
        """
        self.unchanged(s, from3=True)


if __name__ == '__main__':
    unittest.main()

# -*- coding: utf-8 -*-
"""
This module contains snippets of Python 3 code (invalid Python 2) and
tests for whether they can be passed to ``pasteurize`` and
immediately run under both Python 2 and Python 3.
"""

from __future__ import print_function, absolute_import

import pprint
from subprocess import Popen, PIPE
import tempfile
import os

from future.tests.base import CodeHandler, unittest, skip26


class TestPasteurize(CodeHandler):
    """
    After running ``pasteurize``, these Python 3 code snippets should run
    on both Py3 and Py2.
    """

    def setUp(self):
        # For tests that need a text file:
        _, self.textfilename = tempfile.mkstemp(text=True)
        super(TestPasteurize, self).setUp()

    def tearDown(self):
        os.unlink(self.textfilename)

    @skip26    # Python 2.6's lib2to3 causes the "from builtins import
               # range" line to be stuck at the bottom of the module!
    def test_range_slice(self):
        """
        After running ``pasteurize``, this Python 3 code should run
        quickly on both Py3 and Py2 without a MemoryError
        """
        code = '''
        for i in range(10**8)[:10]:
            pass
        '''
        self.unchanged(code, from3=True)

    def test_print(self):
        """
        This Python 3-only code is a SyntaxError on Py2 without the
        print_function import from __future__.
        """
        code = '''
        import sys
        print('Hello', file=sys.stderr)
        '''
        self.unchanged(code, from3=True)

    def test_division(self):
        """
        True division should not be screwed up by conversion from 3 to both
        """
        code = '''
        x = 3 / 2
        assert x == 1.5
        '''
        self.unchanged(code, from3=True)

    # TODO: write / fix the raise_ fixer so that it uses the raise_ function
    @unittest.expectedFailure
    def test_exception_indentation(self):
        """
        As of v0.11.2, pasteurize broke the indentation of ``raise`` statements
        using with_traceback. Test for this.
        """
        before = '''
        import sys
        if True:
            try:
                'string' + 1
            except TypeError:
                ty, va, tb = sys.exc_info()
                raise TypeError("can't do that!").with_traceback(tb)
        '''
        after = '''
        import sys
        from future.utils import raise_with_traceback
        if True:
            try:
                'string' + 1
            except TypeError:
                ty, va, tb = sys.exc_info()
                raise_with_traceback(TypeError("can't do that!"), tb)
        '''
        self.convert_check(before, after, from3=True)

    # TODO: fix and test this test
    @unittest.expectedFailure
    def test_urllib_request(self):
        """
        Example Python 3 code using the new urllib.request module.

        Does the ``pasteurize`` script handle this?
        """
        before = """
            import pprint
            import urllib.request

            URL = 'http://pypi.python.org/pypi/{}/json'
            package = 'future'

            r = urllib.request.urlopen(URL.format(package))
            pprint.pprint(r.read())
        """
        after = """
            import pprint
            import future.standard_library.urllib.request as urllib_request

            URL = 'http://pypi.python.org/pypi/{}/json'
            package = 'future'

            r = urllib_request.urlopen(URL.format(package))
            pprint.pprint(r.read())
        """

        self.convert_check(before, after, from3=True)

    def test_urllib_refactor2(self):
        before = """
        import urllib.request, urllib.parse

        f = urllib.request.urlopen(url, timeout=15)
        filename = urllib.parse.urlparse(url)[2].split('/')[-1]
        """

        after = """
        from future.standard_library.urllib import request as urllib_request
        from future.standard_library.urllib import parse as urllib_parse

        f = urllib_request.urlopen(url, timeout=15)
        filename = urllib_parse.urlparse(url)[2].split('/')[-1]
        """

    def test_correct_exit_status(self):
        """
        Issue #119: futurize and pasteurize were not exiting with the correct
        status code. This is because the status code returned from
        libfuturize.main.main() etc. was a ``newint``, which sys.exit() always
        translates into 1!
        """
        from libpasteurize.main import main
        # Try pasteurizing this test script:
        retcode = main([self.textfilename])
        self.assertTrue(isinstance(retcode, int))   # i.e. Py2 builtin int


class TestFuturizeAnnotations(CodeHandler):
    @unittest.expectedFailure
    def test_return_annotations_alone(self):
        before = "def foo() -> 'bar': pass"
        after = """
        def foo(): pass
        foo.__annotations__ = {'return': 'bar'}
        """
        self.convert_check(before, after, from3=True)

        b = """
        def foo() -> "bar":
            print "baz"
            print "what's next, again?"
        """
        a = """
        def foo():
            print "baz"
            print "what's next, again?"
        """
        self.convert_check(b, a, from3=True)

    @unittest.expectedFailure
    def test_single_param_annotations(self):
        b = "def foo(bar:'baz'): pass"
        a = """
        def foo(bar): pass
        foo.__annotations__ = {'bar': 'baz'}
        """
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"baz"="spam"):
            print("what's next, again?")
            print("whatever.")
        """
        a = """
        def foo(bar="spam"):
            print("what's next, again?")
            print("whatever.")
        foo.__annotations__ = {'bar': 'baz'}
        """
        self.convert_check(b, a, from3=True)

    def test_multiple_param_annotations(self):
        b = "def foo(bar:'spam'=False, baz:'eggs'=True, ham:False='spaghetti'): pass"
        a = "def foo(bar=False, baz=True, ham='spaghetti'): pass"
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"spam"=False, baz:"eggs"=True, ham:False="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        a = """
        def foo(bar=False, baz=True, ham="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        self.convert_check(b, a, from3=True)

    def test_mixed_annotations(self):
        b = "def foo(bar=False, baz:'eggs'=True, ham:False='spaghetti') -> 'zombies': pass"
        a = "def foo(bar=False, baz=True, ham='spaghetti'): pass"
        self.convert_check(b, a, from3=True)

        b = """
        def foo(bar:"spam"=False, baz=True, ham:False="spam") -> 'air':
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        a = """
        def foo(bar=False, baz=True, ham="spam"):
            print("this is filler, just doing a suite")
            print("suites require multiple lines.")
        """
        self.convert_check(b, a, from3=True)

        b = "def foo(bar) -> 'brains': pass"
        a = "def foo(bar): pass"
        self.convert_check(b, a, from3=True)

    def test_functions_unchanged(self):
        s = "def foo(): pass"
        self.unchanged(s, from3=True)

        s = """
        def foo():
            pass
            pass
        """
        self.unchanged(s, from3=True)

        s = """
        def foo(bar='baz'):
            pass
            pass
        """
        self.unchanged(s, from3=True)


if __name__ == '__main__':
    unittest.main()

# -*- coding: utf-8 -*- This module contains snippets of Python 3 code (invalid Python 2) and tests for whether they can be passed to ``pasteurize`` and immediately run under both Python 2 and Python 3. After running ``pasteurize``, these Python 3 code snippets should run     on both Py3 and Py2. # For tests that need a text file: # Python 2.6's lib2to3 causes the "from builtins import # range" line to be stuck at the bottom of the module! After running ``pasteurize``, this Python 3 code should run         quickly on both Py3 and Py2 without a MemoryError for i in range(10**8)[:10]:             pass This Python 3-only code is a SyntaxError on Py2 without the         print_function import from __future__. import sys         print('Hello', file=sys.stderr) True division should not be screwed up by conversion from 3 to both x = 3 / 2         assert x == 1.5 # TODO: write / fix the raise_ fixer so that it uses the raise_ function As of v0.11.2, pasteurize broke the indentation of ``raise`` statements         using with_traceback. Test for this. import sys         if True:             try:                 'string' + 1             except TypeError:                 ty, va, tb = sys.exc_info()                 raise TypeError("can't do that!").with_traceback(tb) import sys         from future.utils import raise_with_traceback         if True:             try:                 'string' + 1             except TypeError:                 ty, va, tb = sys.exc_info()                 raise_with_traceback(TypeError("can't do that!"), tb) # TODO: fix and test this test Example Python 3 code using the new urllib.request module.          Does the ``pasteurize`` script handle this? import pprint             import urllib.request              URL = 'http://pypi.python.org/pypi/{}/json'             package = 'future'              r = urllib.request.urlopen(URL.format(package))             pprint.pprint(r.read()) import pprint             import future.standard_library.urllib.request as urllib_request              URL = 'http://pypi.python.org/pypi/{}/json'             package = 'future'              r = urllib_request.urlopen(URL.format(package))             pprint.pprint(r.read()) import urllib.request, urllib.parse          f = urllib.request.urlopen(url, timeout=15)         filename = urllib.parse.urlparse(url)[2].split('/')[-1] from future.standard_library.urllib import request as urllib_request         from future.standard_library.urllib import parse as urllib_parse          f = urllib_request.urlopen(url, timeout=15)         filename = urllib_parse.urlparse(url)[2].split('/')[-1] Issue #119: futurize and pasteurize were not exiting with the correct         status code. This is because the status code returned from         libfuturize.main.main() etc. was a ``newint``, which sys.exit() always         translates into 1! # Try pasteurizing this test script: # i.e. Py2 builtin int def foo(): pass         foo.__annotations__ = {'return': 'bar'} def foo() -> "bar":             print "baz"             print "what's next, again?" def foo():             print "baz"             print "what's next, again?" def foo(bar): pass         foo.__annotations__ = {'bar': 'baz'} def foo(bar:"baz"="spam"):             print("what's next, again?")             print("whatever.") def foo(bar="spam"):             print("what's next, again?")             print("whatever.")         foo.__annotations__ = {'bar': 'baz'} def foo(bar:"spam"=False, baz:"eggs"=True, ham:False="spam"):             print("this is filler, just doing a suite")             print("suites require multiple lines.") def foo(bar=False, baz=True, ham="spam"):             print("this is filler, just doing a suite")             print("suites require multiple lines.") def foo(bar:"spam"=False, baz=True, ham:False="spam") -> 'air':             print("this is filler, just doing a suite")             print("suites require multiple lines.") def foo(bar=False, baz=True, ham="spam"):             print("this is filler, just doing a suite")             print("suites require multiple lines.") def foo():             pass             pass def foo(bar='baz'):             pass             pass