Bug 2196785 - python-decopatch fails to build with Python 3.12: tests ouputs differs from expectations
Summary: python-decopatch fails to build with Python 3.12: tests ouputs differs from ...
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: python-decopatch
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Zbigniew Jędrzejewski-Szmek
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.12
TreeView+ depends on / blocked
 
Reported: 2023-05-10 08:55 UTC by Tomáš Hrnčiar
Modified: 2023-07-29 14:05 UTC (History)
5 users (show)

Fixed In Version: python-decopatch-1.4.10-11.fc39
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-07-29 14:05:23 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Github smarie python-decopatch issues 32 0 None open tests fail with python 3.12 2023-05-29 07:44:08 UTC

Description Tomáš Hrnčiar 2023-05-10 08:55:20 UTC
python-decopatch fails to build with Python 3.12.0a7.

=================================== FAILURES ===================================
__________________________ test_doc_say_hello[nested] __________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fdf0d78bd40>
mode = 'nested'

    @pytest.mark.parametrize('mode', ['nested', 'flat', 'double-flat'])
    def test_doc_say_hello(capsys, mode):
        """ Tests that the @say_hello example from doc works """
    
        with capsys.disabled():
            if mode == 'nested':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
            elif mode == 'flat':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
    
            elif mode == 'double-flat':
                @function_decorator
                def say_hello(person="world", f=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
                    print("hello, %s !" % person)  # say hello
                    return f(*f_args, **f_kwargs)  # call f
    
            else:
                raise ValueError("unsupported mode : %s" % mode)
    
        # for debug..
        with capsys.disabled():
            @say_hello  # no parenthesis
            def foo():
                print("<executing foo>")
    
        # for debug..
        with capsys.disabled():
            foo()
    
        foo()
    
        @say_hello()  # empty parenthesis
        def bar():
            print("<executing bar>")
    
        bar()
    
        @say_hello("you")  # arg
        def custom():
            print("<executing custom>")
    
        custom()
    
        # manual decoration
        def custom2():
            print("<executing custom2>")
    
        custom2 = say_hello()(custom2)
        custom2()
    
        help(say_hello)
    
        assert str(signature(say_hello)) == "(person='world')"
    
        print("Signature: %s" % signature(say_hello))
    
        @say_hello  # no parenthesis
        def add_ints(a, b):
            return a + b
    
        assert add_ints(1, 3) == 4
    
        captured = capsys.readouterr()
        with capsys.disabled():
            print(captured.out)
    
>       assert captured.out == """hello, world !
    <executing foo>
    hello, world !
    <executing bar>
    hello, you !
    <executing custom>
    hello, world !
    <executing custom2>
    Help on function say_hello in module tests.test_doc:
    
    say_hello(person='world')
        This decorator wraps the decorated function so that a nice hello
        message is printed before each call.
    
        :param person: the person name in the print message. Default = "world"
    
    Signature: (person='world')
    hello, world !
    """
E       assert 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n\n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n' == 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n    \n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n'
E           hello, world !
E           <executing foo>
E           hello, world !
E           <executing bar>
E           hello, you !
E           <executing custom>
E           hello, world !
E           <executing custom2>
E           Help on function say_hello in module tests.test_doc:
E           
E           say_hello(person='world')
E               This decorator wraps the decorated function so that a nice hello
E               message is printed before each call.
E         -     
E         + 
E               :param person: the person name in the print message. Default = "world"
E           
E           Signature: (person='world')
E           hello, world !

tests/test_doc.py:185: AssertionError
___________________________ test_doc_say_hello[flat] ___________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fdf0d44d7f0>
mode = 'flat'

    @pytest.mark.parametrize('mode', ['nested', 'flat', 'double-flat'])
    def test_doc_say_hello(capsys, mode):
        """ Tests that the @say_hello example from doc works """
    
        with capsys.disabled():
            if mode == 'nested':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
            elif mode == 'flat':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
    
            elif mode == 'double-flat':
                @function_decorator
                def say_hello(person="world", f=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
                    print("hello, %s !" % person)  # say hello
                    return f(*f_args, **f_kwargs)  # call f
    
            else:
                raise ValueError("unsupported mode : %s" % mode)
    
        # for debug..
        with capsys.disabled():
            @say_hello  # no parenthesis
            def foo():
                print("<executing foo>")
    
        # for debug..
        with capsys.disabled():
            foo()
    
        foo()
    
        @say_hello()  # empty parenthesis
        def bar():
            print("<executing bar>")
    
        bar()
    
        @say_hello("you")  # arg
        def custom():
            print("<executing custom>")
    
        custom()
    
        # manual decoration
        def custom2():
            print("<executing custom2>")
    
        custom2 = say_hello()(custom2)
        custom2()
    
        help(say_hello)
    
        assert str(signature(say_hello)) == "(person='world')"
    
        print("Signature: %s" % signature(say_hello))
    
        @say_hello  # no parenthesis
        def add_ints(a, b):
            return a + b
    
        assert add_ints(1, 3) == 4
    
        captured = capsys.readouterr()
        with capsys.disabled():
            print(captured.out)
    
>       assert captured.out == """hello, world !
    <executing foo>
    hello, world !
    <executing bar>
    hello, you !
    <executing custom>
    hello, world !
    <executing custom2>
    Help on function say_hello in module tests.test_doc:
    
    say_hello(person='world')
        This decorator wraps the decorated function so that a nice hello
        message is printed before each call.
    
        :param person: the person name in the print message. Default = "world"
    
    Signature: (person='world')
    hello, world !
    """
E       assert 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n\n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n' == 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n    \n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n'
E           hello, world !
E           <executing foo>
E           hello, world !
E           <executing bar>
E           hello, you !
E           <executing custom>
E           hello, world !
E           <executing custom2>
E           Help on function say_hello in module tests.test_doc:
E           
E           say_hello(person='world')
E               This decorator wraps the decorated function so that a nice hello
E               message is printed before each call.
E         -     
E         + 
E               :param person: the person name in the print message. Default = "world"
E           
E           Signature: (person='world')
E           hello, world !

tests/test_doc.py:185: AssertionError
_______________________ test_doc_say_hello[double-flat] ________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fdf0d43bd40>
mode = 'double-flat'

    @pytest.mark.parametrize('mode', ['nested', 'flat', 'double-flat'])
    def test_doc_say_hello(capsys, mode):
        """ Tests that the @say_hello example from doc works """
    
        with capsys.disabled():
            if mode == 'nested':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
            elif mode == 'flat':
                @function_decorator
                def say_hello(person="world", f=DECORATED):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
    
                    # create a wrapper of f that will do the print before call
                    # we rely on `makefun.wraps` to preserve signature
                    @wraps(f)
                    def new_f(*args, **kwargs):
                        print("hello, %s !" % person)  # say hello
                        return f(*args, **kwargs)  # call f
    
                    # return the new function
                    return new_f
    
            elif mode == 'double-flat':
                @function_decorator
                def say_hello(person="world", f=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS):
                    """
                    This decorator wraps the decorated function so that a nice hello
                    message is printed before each call.
    
                    :param person: the person name in the print message. Default = "world"
                    """
                    print("hello, %s !" % person)  # say hello
                    return f(*f_args, **f_kwargs)  # call f
    
            else:
                raise ValueError("unsupported mode : %s" % mode)
    
        # for debug..
        with capsys.disabled():
            @say_hello  # no parenthesis
            def foo():
                print("<executing foo>")
    
        # for debug..
        with capsys.disabled():
            foo()
    
        foo()
    
        @say_hello()  # empty parenthesis
        def bar():
            print("<executing bar>")
    
        bar()
    
        @say_hello("you")  # arg
        def custom():
            print("<executing custom>")
    
        custom()
    
        # manual decoration
        def custom2():
            print("<executing custom2>")
    
        custom2 = say_hello()(custom2)
        custom2()
    
        help(say_hello)
    
        assert str(signature(say_hello)) == "(person='world')"
    
        print("Signature: %s" % signature(say_hello))
    
        @say_hello  # no parenthesis
        def add_ints(a, b):
            return a + b
    
        assert add_ints(1, 3) == 4
    
        captured = capsys.readouterr()
        with capsys.disabled():
            print(captured.out)
    
>       assert captured.out == """hello, world !
    <executing foo>
    hello, world !
    <executing bar>
    hello, you !
    <executing custom>
    hello, world !
    <executing custom2>
    Help on function say_hello in module tests.test_doc:
    
    say_hello(person='world')
        This decorator wraps the decorated function so that a nice hello
        message is printed before each call.
    
        :param person: the person name in the print message. Default = "world"
    
    Signature: (person='world')
    hello, world !
    """
E       assert 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n\n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n' == 'hello, world !\n<executing foo>\nhello, world !\n<executing bar>\nhello, you !\n<executing custom>\nhello, world !\n<executing custom2>\nHelp on function say_hello in module tests.test_doc:\n\nsay_hello(person=\'world\')\n    This decorator wraps the decorated function so that a nice hello\n    message is printed before each call.\n    \n    :param person: the person name in the print message. Default = "world"\n\nSignature: (person=\'world\')\nhello, world !\n'
E           hello, world !
E           <executing foo>
E           hello, world !
E           <executing bar>
E           hello, you !
E           <executing custom>
E           hello, world !
E           <executing custom2>
E           Help on function say_hello in module tests.test_doc:
E           
E           say_hello(person='world')
E               This decorator wraps the decorated function so that a nice hello
E               message is printed before each call.
E         -     
E         + 
E               :param person: the person name in the print message. Default = "world"
E           
E           Signature: (person='world')
E           hello, world !

tests/test_doc.py:185: AssertionError
________________________ test_doc_impl_first_say_hello _________________________

capsys = <_pytest.capture.CaptureFixture object at 0x7fdf0d44fc50>

    def test_doc_impl_first_say_hello(capsys):
        """The second implementation-first example in the doc"""
    
        @function_decorator
        def say_hello(person='world', f=DECORATED):
            """
            This decorator modifies the decorated function so that a nice hello
            message is printed before the call.
    
            :param person: the person name in the print message. Default = "world"
            :param f: represents the decorated item. Automatically injected.
            :return: a modified version of `f` that will print a hello message before executing
            """
    
            # create a wrapper of f that will do the print before call
            # we rely on `makefun.wraps` to preserve signature
            @wraps(f)
            def new_f(*args, **kwargs):
                # nonlocal person
                person = new_f.person
                print("hello, %s !" % person)  # say hello
                return f(*args, **kwargs)  # call f
    
            # we use the trick at https://stackoverflow.com/a/16032631/7262247
            # to access the nonlocal 'person' variable in python 2 and 3
            # for python 3 only you can use 'nonlocal' https://www.python.org/dev/peps/pep-3104/
            new_f.person = person
    
            # return the wrapper
            return new_f
    
        @say_hello
        def foo(a, b):
            return a + b
    
        @say_hello()
        def bar(a, b):
            return a + b
    
        @say_hello("you")
        def custom(a, b):
            return a + b
    
        assert foo(1, 3) == 4
        assert bar(1, 3) == 4
        assert custom(1, 3) == 4
    
        help(say_hello)
    
        print("Signature: %s" % signature(say_hello))
    
        captured = capsys.readouterr()
        with capsys.disabled():
            print(captured.out)
    
>       assert captured.out == """hello, world !
    hello, world !
    hello, you !
    Help on function say_hello in module tests.test_doc_advanced:
    
    say_hello(person='world')
        This decorator modifies the decorated function so that a nice hello
        message is printed before the call.
    
        :param person: the person name in the print message. Default = "world"
        :param f: represents the decorated item. Automatically injected.
        :return: a modified version of `f` that will print a hello message before executing
    
    Signature: (person='world')
    """
E       assert 'hello, world !\nhello, world !\nhello, you !\nHelp on function say_hello in module tests.test_doc_advanced:\n\nsay_hello(person=\'world\')\n    This decorator modifies the decorated function so that a nice hello\n    message is printed before the call.\n\n    :param person: the person name in the print message. Default = "world"\n    :param f: represents the decorated item. Automatically injected.\n    :return: a modified version of `f` that will print a hello message before executing\n\nSignature: (person=\'world\')\n' == 'hello, world !\nhello, world !\nhello, you !\nHelp on function say_hello in module tests.test_doc_advanced:\n\nsay_hello(person=\'world\')\n    This decorator modifies the decorated function so that a nice hello\n    message is printed before the call.\n    \n    :param person: the person name in the print message. Default = "world"\n    :param f: represents the decorated item. Automatically injected.\n    :return: a modified version of `f` that will print a hello message before executing\n\nSignature: (person=\'world\')\n'
E           hello, world !
E           hello, world !
E           hello, you !
E           Help on function say_hello in module tests.test_doc_advanced:
E           
E           say_hello(person='world')
E               This decorator modifies the decorated function so that a nice hello
E               message is printed before the call.
E         -     
E         + 
E               :param person: the person name in the print message. Default = "world"
E               :param f: represents the decorated item. Automatically injected.
E               :return: a modified version of `f` that will print a hello message before executing
E           
E           Signature: (person='world')

tests/test_doc_advanced.py:203: AssertionError
=========================== short test summary info ============================
FAILED tests/test_doc.py::test_doc_say_hello[nested] - assert 'hello, world !...
FAILED tests/test_doc.py::test_doc_say_hello[flat] - assert 'hello, world !\n...
FAILED tests/test_doc.py::test_doc_say_hello[double-flat] - assert 'hello, wo...
FAILED tests/test_doc_advanced.py::test_doc_impl_first_say_hello - assert 'he...
================== 4 failed, 182 passed, 80 skipped in 0.58s ===================

https://docs.python.org/3.12/whatsnew/3.12.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.12/fedora-rawhide-x86_64/05901542-python-decopatch/

For all our attempts to build python-decopatch with Python 3.12, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.12/package/python-decopatch/

Testing and mass rebuild of packages is happening in copr. You can follow these instructions to test locally in mock if your package builds with Python 3.12:
https://copr.fedorainfracloud.org/coprs/g/python/python3.12/

Let us know here if you have any questions.

Python 3.12 is planned to be included in Fedora 39. To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.12.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires), so if this package is required a lot, it's important for us to get it fixed soon.
We'd appreciate help from the people who know this package best, but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 Zbigniew Jędrzejewski-Szmek 2023-05-29 07:44:09 UTC
https://github.com/smarie/python-decopatch/issues/32

Comment 2 Zbigniew Jędrzejewski-Szmek 2023-07-29 14:05:23 UTC
The issue is open, but the package was built.


Note You need to log in before you can comment on or make changes to this bug.