GitPython icon indicating copy to clipboard operation
GitPython copied to clipboard

repo.index.commit fails on python 3.10.0-rc2 (but not 3.10.0-rc1)

Open muggenhor opened this issue 4 years ago • 5 comments

This is an excerpt of Hopic's pytest run in the python:3.10.0rc2-slim docker image. With python:3.10.0rc1-slim this same error does not occur.

I don't have the time right now to fully analyze this. But it looks suspiciously similar to a problem that I observed in Hopic itself and fixed with tomtom-international/hopic@a0f5a93b6c2efbfcd607e4a4927b655984564fb9. That one was triggered by this Python change: https://bugs.python.org/issue44806 / python/cpython@2cc19a5463c804b2f39b94de896d55dcb57a364c.

This if failing in a different location in the same function. But given the CPython commit message it seems to me that it's somehow achieving the opposite of its intent: it looks like non-protocol classes do call the __init__ method (via super) of the protocol class they inherit from.

>           repo.index.commit(message='Initial commit', **_commitargs)                                                                                             [2921/9962]
                                                                                                                                                                              
hopic/test/test_version_bump.py:173:                                                                                                                                          
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.tox/py310/lib/python3.10/site-packages/git/index/base.py:1002: in commit                                                                                                     
    rval = Commit.create_from_tree(self.repo, tree, message, parent_commits,                                                                                                  
.tox/py310/lib/python3.10/site-packages/git/objects/commit.py:459: in create_from_tree                                                                                        
    new_commit = cls(repo, cls.NULL_BIN_SHA, tree,                                                                                                                            
.tox/py310/lib/python3.10/site-packages/git/objects/commit.py:130: in __init__                                                                                                
    super(Commit, self).__init__(repo, binsha)                                                                                                                                
.tox/py310/lib/python3.10/site-packages/git/objects/base.py:57: in __init__                                                                                                       super(Object, self).__init__()                                                                                                                                            
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <[AttributeError("'Commit' object has no attribute 'binsha'") raised in repr()] Commit object at 0x7f669cbdc8b0>, args = (), kwargs = {}
cls = <class 'git.objects.commit.Commit'>, base = <class 'git.objects.commit.Commit'>, init = <function Commit.__init__ at 0x7f669d820af0>

    def _no_init_or_replace_init(self, *args, **kwargs):
        cls = type(self)
     
        if cls._is_protocol:
            raise TypeError('Protocols cannot be instantiated')
     
        # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
        # The first instantiation of the subclass will call `_no_init_or_replace_init` which
        # searches for a proper new `__init__` in the MRO. The new `__init__`
        # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
        # instantiation of the protocol subclass will thus use the new
        # `__init__` and no longer call `_no_init_or_replace_init`.
        for base in cls.__mro__:
            init = base.__dict__.get('__init__', _no_init_or_replace_init)
            if init is not _no_init_or_replace_init:
                cls.__init__ = init
                break
        else:
            # should not happen
            cls.__init__ = object.__init__
     
>       cls.__init__(self, *args, **kwargs) 
E       TypeError: Commit.__init__() missing 2 required positional arguments: 'repo' and 'binsha'

/usr/local/lib/python3.10/typing.py:1422: TypeError

muggenhor avatar Sep 10 '21 13:09 muggenhor

Thanks for reporting. I wouldn't know how to go about this though. Is it a bug in the upcoming python release and thus should be reported there? Or is it a 'breaking-change-in-minor-release' that is justified as bugfix so GitPython should be adjusted?

Admittedly, GItPython clearly fell into the OO trap and probably pays for that more than a decade later, so cleaning this up is probably merely paying tech debt (with a lot of accumulated compound interest ;)).

Byron avatar Sep 10 '21 14:09 Byron

Yeah, i think this is the same issue with Protocol classes that cropped up a few times. #1332 Our Protocol classes worked for 3.10.0.b4, then broke in rc1. I fixed that, and then it broke again in rc2 😭.

I have to check if we can just revert to the our original code or it needs a different fix. I might end up just stripping Protocols back out like I did for TypeGuard, until python changes calm down. Either way, we'll need a new GitPython release for py 3.10.0 compat (due Oct 4th).

Yobmod avatar Sep 24 '21 01:09 Yobmod

Having a similar issue with Python 3.9.7. Is it related or should I open a new issue?

>           repo.index.commit("First commit")

test/test_lib.py:960: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../.cache/pypoetry/virtualenvs/arduino-cli-P0JdEWiU-py3.9/lib/python3.9/site-packages/git/index/base.py:1000: in commit
    tree = self.write_tree()
../../.cache/pypoetry/virtualenvs/arduino-cli-P0JdEWiU-py3.9/lib/python3.9/site-packages/git/index/base.py:574: in write_tree
    root_tree = Tree(self.repo, binsha, path='')
../../.cache/pypoetry/virtualenvs/arduino-cli-P0JdEWiU-py3.9/lib/python3.9/site-packages/git/objects/tree.py:215: in __init__
    super(Tree, self).__init__(repo, binsha, mode, path)
../../.cache/pypoetry/virtualenvs/arduino-cli-P0JdEWiU-py3.9/lib/python3.9/site-packages/git/objects/base.py:168: in __init__
    super(IndexObject, self).__init__(repo, binsha)
../../.cache/pypoetry/virtualenvs/arduino-cli-P0JdEWiU-py3.9/lib/python3.9/site-packages/git/objects/base.py:56: in __init__
    super(Object, self).__init__()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <[AttributeError('binsha') raised in repr()] Tree object at 0x7f5858690db0>, args = (), kwargs = {}

    def _no_init(self, *args, **kwargs):
>       raise TypeError('Protocols cannot be instantiated')
E       TypeError: Protocols cannot be instantiated

/usr/lib/python3.9/typing.py:1083: TypeError

silvanocerza avatar Sep 24 '21 12:09 silvanocerza

@silvanocerza different stack trace but the same issue as far as I can tell (i.e. triggered by inheritance from typing.Protocol).

muggenhor avatar Sep 24 '21 15:09 muggenhor

The issue is not present in Python 3.9.6 by the way.

silvanocerza avatar Sep 24 '21 15:09 silvanocerza

I also got the error in the original post with Python 3.10.0-rc2. But it worked fine with the final release of Python 3.10.0, which I guess explains why this issue hasn't had any activity over the last year. So I think it can be closed.

mhsmith avatar Sep 27 '22 20:09 mhsmith