Skip to content

Commit 05cde6c

Browse files
committed
No longer mock builtins.open in tests
1 parent 825daba commit 05cde6c

File tree

6 files changed

+62
-60
lines changed

6 files changed

+62
-60
lines changed

ci/checks/enforce-mocking-only-whitelisted-methods.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ set -e -o pipefail -u
44

55
self_name=$(basename "$0")
66

7+
# Note that builtins.open should NOT be mocked as it can interfere with coverage.py,
8+
# see https://github.com/coveragepy/coveragepy/issues/2083#issuecomment-3521840036
79
whitelisted_methods="\
810
builtins.input
9-
builtins.open
1011
git_machete.code_hosting.OrganizationAndRepository.from_url
1112
git_machete.git_operations.GitContext.fetch_remote
1213
git_machete.github.GitHubClient.MAX_PULLS_PER_PAGE_COUNT
@@ -18,6 +19,7 @@ git_machete.utils._run_cmd
1819
git_machete.utils.find_executable
1920
git_machete.utils.get_current_date
2021
git_machete.utils.is_stdout_a_tty
22+
git_machete.utils.slurp_file
2123
os.path.isfile
2224
shutil.which
2325
sys.argv

docs/man/git-machete.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
2727
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
2828
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
2929
..
30-
.TH "GIT-MACHETE" "1" "Nov 11, 2025" "" "git-machete"
30+
.TH "GIT-MACHETE" "1" "Nov 12, 2025" "" "git-machete"
3131
.SH NAME
3232
git-machete \- git-machete 3.37.1
3333
.sp

git_machete/github.py

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99
from pathlib import Path
1010
from typing import Any, Dict, List, NamedTuple, Optional, Tuple
1111

12-
from .code_hosting import (CodeHostingClient, CodeHostingGitConfigKeys,
13-
CodeHostingSpec, OrganizationAndRepository,
14-
OrganizationAndRepositoryAndGitUrl, PullRequest)
15-
from .exceptions import MacheteException, UnexpectedMacheteException
16-
from .git_operations import LocalBranchShortName
17-
from .utils import bold, compact_dict, debug, popen_cmd, warn
12+
from git_machete import utils
13+
from git_machete.code_hosting import (CodeHostingClient,
14+
CodeHostingGitConfigKeys,
15+
CodeHostingSpec,
16+
OrganizationAndRepository,
17+
OrganizationAndRepositoryAndGitUrl,
18+
PullRequest)
19+
from git_machete.exceptions import MacheteException, UnexpectedMacheteException
20+
from git_machete.git_operations import LocalBranchShortName
21+
from git_machete.utils import bold, compact_dict, debug, popen_cmd, warn
1822

1923
GITHUB_TOKEN_ENV_VAR = 'GITHUB_TOKEN'
2024

@@ -48,19 +52,18 @@ def __get_token_from_file_in_home_directory(cls, domain: str) -> Optional["GitHu
4852

4953
if os.path.isfile(file_full_path):
5054
debug(f" File `{file_full_path}` exists")
51-
with open(file_full_path) as file:
52-
# ~/.github-token is a file with a structure similar to:
53-
#
54-
# ghp_mytoken_for_github_com
55-
# ghp_myothertoken_for_git_example_org git.example.org
56-
# ghp_yetanothertoken_for_git_example_com git.example.com
57-
58-
for line in file.readlines():
59-
if line.rstrip().endswith(" " + domain):
60-
token = line.split(" ")[0]
61-
return cls(value=token, provider=provider)
62-
elif domain == GitHubClient.DEFAULT_GITHUB_DOMAIN and " " not in line.rstrip():
63-
return cls(value=line.rstrip(), provider=provider)
55+
56+
# ~/.github-token is a file with a structure similar to:
57+
#
58+
# ghp_mytoken_for_github_com
59+
# ghp_myothertoken_for_git_example_org git.example.org
60+
# ghp_yetanothertoken_for_git_example_com git.example.com
61+
for line in utils.slurp_file(file_full_path).splitlines():
62+
if line.rstrip().endswith(" " + domain):
63+
token = line.split(" ")[0]
64+
return cls(value=token, provider=provider)
65+
elif domain == GitHubClient.DEFAULT_GITHUB_DOMAIN and " " not in line.rstrip():
66+
return cls(value=line.rstrip(), provider=provider)
6467
return None
6568

6669
@classmethod
@@ -121,26 +124,25 @@ def __get_token_from_hub(cls, domain: str) -> Optional["GitHubToken"]:
121124
home_path: str = str(Path.home())
122125
config_hub_path: str = os.path.join(home_path, ".config", "hub")
123126
if os.path.isfile(config_hub_path):
124-
with open(config_hub_path) as config_hub:
125-
# ~/.config/hub is a yaml file, with a structure similar to:
126-
#
127-
# {domain1}:
128-
# - user: {username1}
129-
# oauth_token: *******************
130-
# protocol: {protocol}
131-
#
132-
# {domain2}:
133-
# - user: {username2}
134-
# oauth_token: *******************
135-
# protocol: {protocol}
136-
found_host = False
137-
for line in config_hub.readlines():
138-
if line.rstrip() == domain + ":":
139-
found_host = True
140-
elif found_host and line.lstrip().startswith("oauth_token:"):
141-
result = re.sub(' *oauth_token: +', '', line).rstrip().replace('"', '')
142-
return cls(value=result,
143-
provider=f'auth token for {domain} from `hub` GitHub CLI')
127+
# ~/.config/hub is a yaml file, with a structure similar to:
128+
#
129+
# {domain1}:
130+
# - user: {username1}
131+
# oauth_token: *******************
132+
# protocol: {protocol}
133+
#
134+
# {domain2}:
135+
# - user: {username2}
136+
# oauth_token: *******************
137+
# protocol: {protocol}
138+
found_host = False
139+
for line in utils.slurp_file(config_hub_path).splitlines():
140+
if line.rstrip() == domain + ":":
141+
found_host = True
142+
elif found_host and line.lstrip().startswith("oauth_token:"):
143+
result = re.sub(' *oauth_token: +', '', line).rstrip().replace('"', '')
144+
return cls(value=result,
145+
provider=f'auth token for {domain} from `hub` GitHub CLI')
144146
return None
145147

146148

git_machete/gitlab.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import urllib.request
1010
from typing import Any, Dict, List, NamedTuple, Optional
1111

12+
from git_machete import utils
1213
from git_machete.code_hosting import (CodeHostingClient,
1314
CodeHostingGitConfigKeys,
1415
CodeHostingSpec,
@@ -50,19 +51,18 @@ def __get_token_from_file_in_home_directory(cls, domain: str) -> Optional["GitLa
5051

5152
if os.path.isfile(file_full_path):
5253
debug(f" File `{file_full_path}` exists")
53-
with open(file_full_path) as file:
54-
# ~/.gitlab-token is a file with a structure similar to:
55-
#
56-
# glpat-mytoken_for_gitlab_com
57-
# glpat-myothertoken_for_git_example_org git.example.org
58-
# glpat-yetanothertoken_for_git_example_com git.example.com
59-
60-
for line in file.readlines():
61-
if line.rstrip().endswith(" " + domain):
62-
token = line.split(" ")[0]
63-
return cls(value=token, provider=provider)
64-
elif domain == GitLabClient.DEFAULT_GITLAB_DOMAIN and " " not in line.rstrip():
65-
return cls(value=line.rstrip(), provider=provider)
54+
55+
# ~/.gitlab-token is a file with a structure similar to:
56+
#
57+
# glpat-mytoken_for_gitlab_com
58+
# glpat-myothertoken_for_git_example_org git.example.org
59+
# glpat-yetanothertoken_for_git_example_com git.example.com
60+
for line in utils.slurp_file(file_full_path).splitlines():
61+
if line.rstrip().endswith(" " + domain):
62+
token = line.split(" ")[0]
63+
return cls(value=token, provider=provider)
64+
elif domain == GitLabClient.DEFAULT_GITLAB_DOMAIN and " " not in line.rstrip():
65+
return cls(value=line.rstrip(), provider=provider)
6666
return None
6767

6868
@classmethod

tests/test_github.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from contextlib import contextmanager
33
from textwrap import dedent
44
from typing import Iterator
5-
from unittest.mock import mock_open
65

76
from pytest_mock import MockerFixture
87

@@ -233,7 +232,7 @@ def test_github_get_token_from_file_in_home_directory(self, mocker: MockerFixtur
233232
github_token_contents = ('ghp_mytoken_for_github_com\n'
234233
'ghp_myothertoken_for_git_example_org git.example.org\n'
235234
'ghp_yetanothertoken_for_git_example_com git.example.com')
236-
self.patch_symbol(mocker, 'builtins.open', mock_open(read_data=github_token_contents))
235+
self.patch_symbol(mocker, 'git_machete.utils.slurp_file', lambda _: github_token_contents)
237236
self.patch_symbol(mocker, 'os.path.isfile', lambda _file: True)
238237

239238
domain = GitHubClient.DEFAULT_GITHUB_DOMAIN
@@ -320,8 +319,8 @@ def test_github_get_token_from_hub(self, mocker: MockerFixture) -> None:
320319

321320
# Let's pretend that `gh` is available, but fails for whatever reason.
322321
self.patch_symbol(mocker, 'shutil.which', mock_shutil_which('/path/to/gh'))
323-
self.patch_symbol(mocker, 'os.path.isfile', lambda file: '.github-token' not in file)
324-
self.patch_symbol(mocker, 'builtins.open', mock_open(read_data=dedent(config_hub_contents)))
322+
self.patch_symbol(mocker, 'os.path.isfile', lambda path: '.github-token' not in path)
323+
self.patch_symbol(mocker, 'git_machete.utils.slurp_file', lambda _: dedent(config_hub_contents))
325324

326325
fixed_popen_cmd_results = [(0, "gh version 2.31.0 (2099-12-31)\nhttps://github.com/cli/cli/releases/tag/v2.31.0\n", ""),
327326
(1, "", "unknown error")]

tests/test_gitlab.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import itertools
22
from contextlib import contextmanager
33
from typing import Iterator
4-
from unittest.mock import mock_open
54

65
from pytest_mock import MockerFixture
76

@@ -233,7 +232,7 @@ def test_gitlab_get_token_from_file_in_home_directory(self, mocker: MockerFixtur
233232
gitlab_token_contents = ('glpat-mytoken_for_gitlab_com\n'
234233
'glpat-myothertoken_for_git_example_org git.example.org\n'
235234
'glpat-yetanothertoken_for_git_example_com git.example.com')
236-
self.patch_symbol(mocker, 'builtins.open', mock_open(read_data=gitlab_token_contents))
235+
self.patch_symbol(mocker, 'git_machete.utils.slurp_file', lambda _: gitlab_token_contents)
237236
self.patch_symbol(mocker, 'os.path.isfile', lambda _file: True)
238237

239238
domain = GitLabClient.DEFAULT_GITLAB_DOMAIN

0 commit comments

Comments
 (0)