Skip to content

Commit e155b47

Browse files
authored
Merge pull request #6095 from cjerdonek/freeze-repo-with-no-remote
Address #4759: change freeze to support editable Git repos with no remote
2 parents 740b1ac + 61bb651 commit e155b47

File tree

7 files changed

+72
-22
lines changed

7 files changed

+72
-22
lines changed

news/4759.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Editable Git installs without a remote now freeze as editable.

src/pip/_internal/operations/freeze.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def get_requirement_info(dist):
172172

173173
location = os.path.normcase(os.path.abspath(dist.location))
174174

175-
from pip._internal.vcs import vcs
175+
from pip._internal.vcs import vcs, RemoteNotFoundError
176176
vc_type = vcs.get_backend_type(location)
177177

178178
if not vc_type:
@@ -188,6 +188,15 @@ def get_requirement_info(dist):
188188

189189
try:
190190
req = vc_type().get_src_requirement(location, dist.project_name)
191+
except RemoteNotFoundError:
192+
req = dist.as_requirement()
193+
comments = [
194+
'# Editable {} install with no remote ({})'.format(
195+
vc_type.__name__, req,
196+
)
197+
]
198+
return (location, True, comments)
199+
191200
except BadCommand:
192201
logger.warning(
193202
'cannot determine version of editable source in %s '

src/pip/_internal/vcs/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
logger = logging.getLogger(__name__)
3030

3131

32+
class RemoteNotFoundError(Exception):
33+
pass
34+
35+
3236
class RevOptions(object):
3337

3438
"""
@@ -452,6 +456,9 @@ def get_src_requirement(self, location, project_name):
452456
def get_remote_url(self, location):
453457
"""
454458
Return the url used at location
459+
460+
Raises RemoteNotFoundError if the repository does not have a remote
461+
url configured.
455462
"""
456463
raise NotImplementedError
457464

src/pip/_internal/vcs/git.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
display_path, make_vcs_requirement_url, redact_password_from_url,
1515
)
1616
from pip._internal.utils.temp_dir import TempDirectory
17-
from pip._internal.vcs import VersionControl, vcs
17+
from pip._internal.vcs import RemoteNotFoundError, VersionControl, vcs
1818

1919
urlsplit = urllib_parse.urlsplit
2020
urlunsplit = urllib_parse.urlunsplit
@@ -250,13 +250,24 @@ def update(self, dest, url, rev_options):
250250
self.update_submodules(dest)
251251

252252
def get_remote_url(self, location):
253-
"""Return URL of the first remote encountered."""
254-
remotes = self.run_command(
253+
"""
254+
Return URL of the first remote encountered.
255+
256+
Raises RemoteNotFoundError if the repository does not have a remote
257+
url configured.
258+
"""
259+
# We need to pass 1 for extra_ok_returncodes since the command
260+
# exits with return code 1 if there are no matching lines.
261+
stdout = self.run_command(
255262
['config', '--get-regexp', r'remote\..*\.url'],
256-
show_stdout=False, cwd=location,
263+
extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
257264
)
258-
remotes = remotes.splitlines()
259-
found_remote = remotes[0]
265+
remotes = stdout.splitlines()
266+
try:
267+
found_remote = remotes[0]
268+
except IndexError:
269+
raise RemoteNotFoundError
270+
260271
for remote in remotes:
261272
if remote.startswith('remote.origin.url '):
262273
found_remote = remote

tests/functional/test_freeze.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ def test_freeze_editable_not_vcs(script, tmpdir):
137137
_check_output(result.stdout, expected)
138138

139139

140+
@pytest.mark.git
141+
def test_freeze_editable_git_with_no_remote(script, tmpdir):
142+
"""
143+
Test an editable Git install with no remote url.
144+
"""
145+
pkg_path = _create_test_package(script)
146+
script.pip('install', '-e', pkg_path)
147+
result = script.pip('freeze')
148+
149+
assert result.stderr == ''
150+
151+
# We need to apply os.path.normcase() to the path since that is what
152+
# the freeze code does.
153+
expected = textwrap.dedent("""\
154+
...# Editable Git install with no remote (version-pkg==0.1)
155+
-e {}
156+
...""".format(os.path.normcase(pkg_path)))
157+
_check_output(result.stdout, expected)
158+
159+
140160
@pytest.mark.svn
141161
def test_freeze_svn(script, tmpdir):
142162
"""Test freezing a svn checkout"""

tests/functional/test_install_vcs_git.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -367,20 +367,6 @@ def test_git_with_ambiguous_revs(script):
367367
result.assert_installed('version-pkg', with_files=['.git'])
368368

369369

370-
def test_git_works_with_editable_non_origin_repo(script):
371-
# set up, create a git repo and install it as editable from a local
372-
# directory path
373-
version_pkg_path = _create_test_package(script)
374-
script.pip('install', '-e', version_pkg_path.abspath)
375-
376-
# 'freeze'ing this should not fall over, but should result in stderr output
377-
# warning
378-
result = script.pip('freeze', expect_stderr=True)
379-
assert "Error when trying to get requirement" in result.stderr
380-
assert "Could not determine repository location" in result.stdout
381-
assert "version-pkg==0.1" in result.stdout
382-
383-
384370
def test_editable__no_revision(script):
385371
"""
386372
Test a basic install in editable mode specifying no revision.

tests/functional/test_vcs_git.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
import os
66

7-
from pip._internal.vcs.git import Git
7+
import pytest
8+
9+
from pip._internal.vcs.git import Git, RemoteNotFoundError
810
from tests.lib import _create_test_package, _git_commit, _test_path_to_file_url
911

1012

@@ -93,6 +95,20 @@ def test_get_remote_url(script, tmpdir):
9395
assert remote_url == source_url
9496

9597

98+
def test_get_remote_url__no_remote(script, tmpdir):
99+
"""
100+
Test a repo with no remote.
101+
"""
102+
repo_dir = tmpdir / 'temp-repo'
103+
repo_dir.mkdir()
104+
repo_dir = str(repo_dir)
105+
106+
script.run('git', 'init', cwd=repo_dir)
107+
108+
with pytest.raises(RemoteNotFoundError):
109+
Git().get_remote_url(repo_dir)
110+
111+
96112
def test_get_current_branch(script):
97113
repo_dir = str(script.scratch_path)
98114

0 commit comments

Comments
 (0)