Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork937
Description
Hi, I've faced a problem on Windows with file/directory removal withshutil.rmtree()
. The problem, by itself, is not new and already has known solutions, includinggit.util.rmtree()
. However, just using this function was not enough in my case and I started to dig deeper - there was an error about an open file handle. I discovered there were extra childgit
processes hanging in the process tree, but, unexpectedly, it was happening after all the library objects were removed:
Then I tried to catch and tracePopen
calls from the library and found out this function:
Lines 1190 to 1199 in5b3669e
defget_object_header(self,ref:str)->Tuple[str,str,int]: | |
""" Use this method to quickly examine the type and size of the object behind | |
the given ref. | |
:note: The method will only suffer from the costs of command invocation | |
once and reuses the command in subsequent calls. | |
:return: (hexsha, type_string, size_as_int)""" | |
cmd=self._get_persistent_cmd("cat_file_header","cat_file",batch_check=True) | |
returnself.__get_object_header(cmd,ref) |
From comments and names, it looks like such persistent behavior is intended. There is also theAutoInterrupt
class here:
Lines 367 to 373 in5b3669e
classAutoInterrupt(object): | |
"""Kill/Interrupt the stored process instance once this instance goes out of scope. It is | |
used to prevent processes piling up in case iterators stop reading. | |
Besides all attributes are wired through to the contained process object. | |
The wait method was overridden to perform automatic status code checking | |
and possibly raise.""" |
returned from:
Line 841 in5b3669e
returnself.AutoInterrupt(proc,command) |
The class comment indicates that the process should be killed when the object goes out of scope. To me, it looks like an attempt to imitatethe RAII C++ idiom. Unfortunately, in Python it does not work this way because of garbage collector and the scoping rules. That is, an object that has no references can be removed in any time after it lost its last reference. The "pythonic" way to deal with this behavior is using a context manager (which this class isnot).
My suggestion is to collect these processes and manage them on a library/repo level, or wrap this in a context manager (which is better than just callingwait()
manually in case of exceptions). BTW, probably, the process created is not reused after the first call.
importgitr=git.Repo.init('test_repo')r.index.commit('aa')delr
Upd: I see there is an undocumentedrepo.close()
, which can help, but can have undesired side-effects because of a forced gc call.