Skip to content

Commit d77fadd

Browse files
authored
Merge pull request #1700 from EliahKagan/untangle-skips
Fix bugs affecting exception wrapping in rmtree callback
2 parents 8107cbf + a9b05ec commit d77fadd

File tree

6 files changed

+262
-123
lines changed

6 files changed

+262
-123
lines changed

‎git/objects/submodule/base.py‎

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,37 @@
1-
# need a dict to set bloody .name field
21
fromioimportBytesIO
32
importlogging
43
importos
4+
importos.pathasosp
55
importstat
66
importuuid
77

88
importgit
99
fromgit.cmdimportGit
10-
fromgit.compatimport (
11-
defenc,
12-
is_win,
13-
)
14-
fromgit.configimportSectionConstraint, GitConfigParser, cp
10+
fromgit.compatimportdefenc, is_win
11+
fromgit.configimportGitConfigParser, SectionConstraint, cp
1512
fromgit.excimport (
13+
BadName,
1614
InvalidGitRepositoryError,
1715
NoSuchPathError,
1816
RepositoryDirtyError,
19-
BadName,
2017
)
2118
fromgit.objects.baseimportIndexObject, Object
2219
fromgit.objects.utilimportTraversableIterableObj
23-
2420
fromgit.utilimport (
25-
join_path_native,
26-
to_native_path_linux,
21+
IterableList,
2722
RemoteProgress,
23+
join_path_native,
2824
rmtree,
25+
to_native_path_linux,
2926
unbare_repo,
30-
IterableList,
3127
)
32-
fromgit.utilimportHIDE_WINDOWS_KNOWN_ERRORS
33-
34-
importos.pathasosp
3528

3629
from .utilimport (
30+
SubmoduleConfigParser,
31+
find_first_remote_branch,
3732
mkhead,
3833
sm_name,
3934
sm_section,
40-
SubmoduleConfigParser,
41-
find_first_remote_branch,
4235
)
4336

4437

@@ -1060,28 +1053,13 @@ def remove(
10601053
importgc
10611054

10621055
gc.collect()
1063-
try:
1064-
rmtree(str(wtd))
1065-
exceptExceptionasex:
1066-
ifHIDE_WINDOWS_KNOWN_ERRORS:
1067-
fromunittestimportSkipTest
1068-
1069-
raiseSkipTest("FIXME: fails with: PermissionError\n{}".format(ex)) fromex
1070-
raise
1056+
rmtree(str(wtd))
10711057
# END delete tree if possible
10721058
# END handle force
10731059

10741060
ifnotdry_runandosp.isdir(git_dir):
10751061
self._clear_cache()
1076-
try:
1077-
rmtree(git_dir)
1078-
exceptExceptionasex:
1079-
ifHIDE_WINDOWS_KNOWN_ERRORS:
1080-
fromunittestimportSkipTest
1081-
1082-
raiseSkipTest(f"FIXME: fails with: PermissionError\n{ex}") fromex
1083-
else:
1084-
raise
1062+
rmtree(git_dir)
10851063
# end handle separate bare repository
10861064
# END handle module deletion
10871065

‎git/util.py‎

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,24 @@
55
# the BSD License: https://opensource.org/license/bsd-3-clause/
66

77
fromabcimportabstractmethod
8-
importos.pathasosp
9-
from .compatimportis_win
108
importcontextlib
119
fromfunctoolsimportwraps
1210
importgetpass
1311
importlogging
1412
importos
13+
importos.pathasosp
14+
importpathlib
1515
importplatform
16-
importsubprocess
1716
importre
1817
importshutil
1918
importstat
20-
fromsysimportmaxsize
19+
importsubprocess
20+
importsys
2121
importtime
2222
fromurllib.parseimporturlsplit, urlunsplit
2323
importwarnings
2424

25-
# from git.objects.util import Traversable
25+
from.compatimportis_win
2626

2727
# typing ---------------------------------------------------------
2828

@@ -42,22 +42,17 @@
4242
Tuple,
4343
TypeVar,
4444
Union,
45-
cast,
4645
TYPE_CHECKING,
46+
cast,
4747
overload,
4848
)
4949

50-
importpathlib
51-
5250
ifTYPE_CHECKING:
5351
fromgit.remoteimportRemote
5452
fromgit.repo.baseimportRepo
5553
fromgit.configimportGitConfigParser, SectionConstraint
5654
fromgitimportGit
5755

58-
# from git.objects.base import IndexObject
59-
60-
6156
from .typesimport (
6257
Literal,
6358
SupportsIndex,
@@ -75,7 +70,6 @@
7570

7671
# ---------------------------------------------------------------------
7772

78-
7973
fromgitdb.utilimport ( # NOQA @IgnorePep8
8074
make_sha,
8175
LockedFD, # @UnusedImport
@@ -88,7 +82,6 @@
8882
hex_to_bin, # @UnusedImport
8983
)
9084

91-
9285
# NOTE: Some of the unused imports might be used/imported by others.
9386
# Handle once test-cases are back up and running.
9487
# Most of these are unused here, but are for use by git-python modules so these
@@ -116,14 +109,33 @@
116109

117110
log=logging.getLogger(__name__)
118111

119-
# types############################################################
112+
113+
def_read_env_flag(name: str, default: bool) ->bool:
114+
try:
115+
value=os.environ[name]
116+
exceptKeyError:
117+
returndefault
118+
119+
log.warning(
120+
"The %s environment variable is deprecated. Its effect has never been documented and changes without warning.",
121+
name,
122+
)
123+
124+
adjusted_value=value.strip().lower()
125+
126+
ifadjusted_valuein{"", "0", "false", "no"}:
127+
returnFalse
128+
ifadjusted_valuein{"1", "true", "yes"}:
129+
returnTrue
130+
log.warning("%s has unrecognized value %r, treating as %r.", name, value, default)
131+
returndefault
120132

121133

122134
#: We need an easy way to see if Appveyor TCs start failing,
123135
#: so the errors marked with this var are considered "acknowledged" ones, awaiting remedy,
124136
#: till then, we wish to hide them.
125-
HIDE_WINDOWS_KNOWN_ERRORS=is_winandos.environ.get("HIDE_WINDOWS_KNOWN_ERRORS", True)
126-
HIDE_WINDOWS_FREEZE_ERRORS=is_winandos.environ.get("HIDE_WINDOWS_FREEZE_ERRORS", True)
137+
HIDE_WINDOWS_KNOWN_ERRORS=is_winand_read_env_flag("HIDE_WINDOWS_KNOWN_ERRORS", True)
138+
HIDE_WINDOWS_FREEZE_ERRORS=is_winand_read_env_flag("HIDE_WINDOWS_FREEZE_ERRORS", True)
127139

128140
#{Utility Methods
129141

@@ -177,25 +189,29 @@ def patch_env(name: str, value: str) -> Generator[None, None, None]:
177189

178190

179191
defrmtree(path: PathLike) ->None:
180-
"""Remove the given recursively.
192+
"""Remove the given directory tree recursively.
181193
182-
:note: we use shutilrmtree but adjust its behaviour to see whether files that
183-
couldn't be deleted are read-only. Windows will not remove them in that case"""
194+
:note: We use :func:`shutil.rmtree` but adjust its behaviour to see whether files that
195+
couldn't be deleted are read-only. Windows will not remove them in that case."""
184196

185-
defonerror(func: Callable, path: PathLike, exc_info: str) ->None:
186-
# Is the error an access error ?
197+
defhandler(function: Callable, path: PathLike, _excinfo: Any) ->None:
198+
"""Callback for :func:`shutil.rmtree`. Works either as ``onexc`` or ``onerror``."""
199+
# Is the error an access error?
187200
os.chmod(path, stat.S_IWUSR)
188201

189202
try:
190-
func(path)# Will scream if still not possible to delete.
191-
exceptExceptionasex:
203+
function(path)
204+
exceptPermissionErrorasex:
192205
ifHIDE_WINDOWS_KNOWN_ERRORS:
193206
fromunittestimportSkipTest
194207

195-
raiseSkipTest("FIXME: fails with: PermissionError\n{}".format(ex)) fromex
208+
raiseSkipTest(f"FIXME: fails with: PermissionError\n{ex}") fromex
196209
raise
197210

198-
returnshutil.rmtree(path, False, onerror)
211+
ifsys.version_info>= (3, 12):
212+
shutil.rmtree(path, onexc=handler)
213+
else:
214+
shutil.rmtree(path, onerror=handler)
199215

200216

201217
defrmfile(path: PathLike) ->None:
@@ -995,7 +1011,7 @@ def __init__(
9951011
self,
9961012
file_path: PathLike,
9971013
check_interval_s: float=0.3,
998-
max_block_time_s: int=maxsize,
1014+
max_block_time_s: int=sys.maxsize,
9991015
) ->None:
10001016
"""Configure the instance
10011017

‎test-requirements.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ pre-commit
77
pytest
88
pytest-cov
99
pytest-instafail
10+
pytest-subtests
1011
pytest-sugar

‎test/test_docs.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ def tearDown(self):
2121

2222
gc.collect()
2323

24-
# @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, ## ACTUALLY skipped by `git.submodule.base#L869`.
24+
# ACTUALLY skipped by git.util.rmtree (in local onerror function), from the last call to it via
25+
# git.objects.submodule.base.Submodule.remove (at "handle separate bare repository"), line 1062.
26+
#
27+
# @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
2528
# "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
2629
# "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\test_work_tree_unsupportedryfa60di\\master_repo\\.git\\objects\\pack\\pack-bc9e0787aef9f69e1591ef38ea0a6f566ec66fe3.idx") # noqa E501
2730
@with_rw_directory

‎test/test_submodule.py‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,10 @@ def _do_base_tests(self, rwrepo):
457457
True,
458458
)
459459

460-
# @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, ## ACTUALLY skipped by `git.submodule.base#L869`.
460+
# ACTUALLY skipped by git.util.rmtree (in local onerror function), called via
461+
# git.objects.submodule.base.Submodule.remove at "method(mp)", line 1011.
462+
#
463+
# @skipIf(HIDE_WINDOWS_KNOWN_ERRORS,
461464
# "FIXME: fails with: PermissionError: [WinError 32] The process cannot access the file because"
462465
# "it is being used by another process: "
463466
# "'C:\\Users\\ankostis\\AppData\\Local\\Temp\\tmp95c3z83bnon_bare_test_base_rw\\git\\ext\\gitdb\\gitdb\\ext\\smmap'") # noqa E501
@@ -819,9 +822,11 @@ def test_git_submodules_and_add_sm_with_new_commit(self, rwdir):
819822
assertcommit_sm.binsha==sm_too.binsha
820823
assertsm_too.binsha!=sm.binsha
821824

822-
# @skipIf(HIDE_WINDOWS_KNOWN_ERRORS, ## ACTUALLY skipped by `git.submodule.base#L869`.
823-
# "FIXME: helper.wrapper fails with: PermissionError: [WinError 5] Access is denied: "
824-
# "'C:\\Users\\appveyor\\AppData\\Local\\Temp\\1\\test_work_tree_unsupportedryfa60di\\master_repo\\.git\\objects\\pack\\pack-bc9e0787aef9f69e1591ef38ea0a6f566ec66fe3.idx") # noqa E501
825+
@pytest.mark.xfail(
826+
HIDE_WINDOWS_KNOWN_ERRORS,
827+
reason='"The process cannot access the file because it is being used by another process" on call to sm.move',
828+
raises=PermissionError,
829+
)
825830
@with_rw_directory
826831
deftest_git_submodule_compatibility(self, rwdir):
827832
parent=git.Repo.init(osp.join(rwdir, "parent"))

0 commit comments

Comments
(0)