Skip to content

Commit 71d9e92

Browse files
committed
Fixes #116
This patch changes hashin such that, If the package specified has underscores in its name, but the new package has hyphens, the following occurs * If there is a new version, hashin updates the package in requirements to be the hyphenated name * If there is no new version, the underscored name remains in place Prior to this patch, the 1st case about would not occur. Instead, hashin would append the new version in its hyphenated form to the requirements file and leave the old version in its underscored form in the requirements file.
1 parent a9e2239 commit 71d9e92

File tree

3 files changed

+264
-2
lines changed

3 files changed

+264
-2
lines changed

hashin.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,17 +388,39 @@ def amend_requirements_content(requirements, all_new_lines):
388388
padding = " " * 4
389389

390390
def is_different_lines(old_lines, new_lines, indent):
391+
# This regex is used to only temporarily normalize the names of packages
392+
# in the lines being compared. This results in "old" names matching
393+
# "new" names so that hashin correctly replaces them when it looks for
394+
# them.
395+
rex = re.compile("[-_]")
396+
391397
# This assumes that the package is already mentioned in the old
392398
# requirements. Now we just need to double-check that its lines are
393399
# different.
394400
# The 'new_lines` is what we might intend to replace it with.
395-
old = set([l.strip(" \\") for l in old_lines])
401+
old = set([rex.sub("-", l.strip(" \\")) for l in old_lines])
396402
new = set([indent + x.strip(" \\") for x in new_lines])
397403
return old != new
398404

399405
for package, old_name, new_text in all_new_lines:
406+
# The call to `escape` will turn hyphens into escaped hyphens
407+
#
408+
# ex.
409+
# - becomes \\-
410+
#
411+
escaped = re.escape(old_name)
412+
413+
# This changes those escaped hypens into a pattern to match
414+
#
415+
# ex.
416+
# \\- becomes [-_]
417+
#
418+
# This is necessary so that hashin will correctly find underscored (old)
419+
# and hyphenated (new) package names so that it will correctly replace an
420+
# old name with the new name when there is a version update.
421+
escape_replaced = escaped.replace("\\-", "[-_]")
400422
regex = re.compile(
401-
r"^(?P<indent>[ \t]*){0}(\[.*\])?==".format(re.escape(old_name)),
423+
r"^(?P<indent>[ \t]*){0}(\[.*\])?==".format(escape_replaced),
402424
re.IGNORECASE | re.MULTILINE,
403425
)
404426
# if the package wasn't already there, add it to the bottom

tests/test_cli.py

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,26 @@ def test_amend_requirements_content_new():
294294
assert result == requirements + new_lines[2]
295295

296296

297+
def test_amend_requirements_content_new_2():
298+
requirements = (
299+
"""
300+
# empty so far
301+
""".strip()
302+
+ "\n"
303+
)
304+
new_lines = (
305+
"discogs-client",
306+
"Discogs_client",
307+
"""
308+
discogs-client==1.1 \\
309+
--hash=sha256:4d64ed1b9e0e73095f5cfa87f0e97ddb4c840049e8efeb7e63b46118ba1d623a
310+
""".strip()
311+
+ "\n",
312+
)
313+
result = hashin.amend_requirements_content(requirements, [new_lines])
314+
assert result == requirements + new_lines[2]
315+
316+
297317
def test_amend_requirements_different_old_name():
298318
requirements = (
299319
"""
@@ -2665,3 +2685,222 @@ def mock_input(question):
26652685
"hashin", old_version, new_version, force_yes=True
26662686
)
26672687
assert result == "YES"
2688+
2689+
2690+
class TestIssue116:
2691+
"""Tests for validating fix related to GH issue #116
2692+
2693+
https://github.com/peterbe/hashin/issues/116
2694+
"""
2695+
2696+
def test_amend_requirements_content_new_without_env_markers(self):
2697+
requirements = (
2698+
"""
2699+
# empty so far
2700+
""".strip()
2701+
+ "\n"
2702+
)
2703+
new_lines = (
2704+
"discogs-client",
2705+
"discogs-client",
2706+
"""
2707+
discogs-client==1.1 \\
2708+
--hash=sha256:4d64ed1b9e0e73095f5cfa87f0e97ddb4c840049e8efeb7e63b46118ba1d623a
2709+
""".strip()
2710+
+ "\n",
2711+
)
2712+
result = hashin.amend_requirements_content(requirements, [new_lines])
2713+
assert result == requirements + new_lines[2]
2714+
2715+
def test_amend_requirements_content_new_with_env_markers(self):
2716+
requirements = (
2717+
"""
2718+
# empty so far
2719+
""".strip()
2720+
+ "\n"
2721+
)
2722+
new_lines = (
2723+
"discogs-client; python_version <= '3.4'",
2724+
"discogs-client; python_version <= '3.4'",
2725+
"""
2726+
discogs-client==1.1; python_version <= '3.4' \\
2727+
--hash=sha256:4d64ed1b9e0e73095f5cfa87f0e97ddb4c840049e8efeb7e63b46118ba1d623a
2728+
""".strip()
2729+
+ "\n",
2730+
)
2731+
result = hashin.amend_requirements_content(requirements, [new_lines])
2732+
assert result == requirements + new_lines[2]
2733+
2734+
def test_amend_requirements_different_old_name_without_env_markers(self):
2735+
requirements = (
2736+
"""
2737+
readme_renderer==25.0 \\
2738+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2739+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2740+
2741+
""".strip()
2742+
+ "\n"
2743+
)
2744+
2745+
new_lines = (
2746+
"readme-renderer",
2747+
"readme-renderer",
2748+
"""
2749+
readme-renderer==26.0 \\
2750+
--hash=sha256:cbe9db71defedd2428a1589cdc545f9bd98e59297449f69d721ef8f1cfced68d \\
2751+
--hash=sha256:cc4957a803106e820d05d14f71033092537a22daa4f406dfbdd61177e0936376
2752+
2753+
""".strip()
2754+
+ "\n",
2755+
)
2756+
result = hashin.amend_requirements_content(requirements, [new_lines])
2757+
assert result == new_lines[2]
2758+
2759+
def test_amend_requirements_different_old_name_with_env_markers(self):
2760+
requirements = (
2761+
"""
2762+
readme_renderer==25.0; python_version <= "3.4" \\
2763+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2764+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2765+
2766+
""".strip()
2767+
+ "\n"
2768+
)
2769+
2770+
new_lines = (
2771+
"readme-renderer",
2772+
"readme-renderer",
2773+
"""
2774+
readme-renderer==26.0; python_version <= "3.4" \\
2775+
--hash=sha256:cbe9db71defedd2428a1589cdc545f9bd98e59297449f69d721ef8f1cfced68d \\
2776+
--hash=sha256:cc4957a803106e820d05d14f71033092537a22daa4f406dfbdd61177e0936376
2777+
2778+
""".strip()
2779+
+ "\n",
2780+
)
2781+
result = hashin.amend_requirements_content(requirements, [new_lines])
2782+
assert result == new_lines[2]
2783+
2784+
def test_amend_requirements_without_env_markers_same_version(self):
2785+
requirements = (
2786+
"""
2787+
readme_renderer==25.0 \\
2788+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2789+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2790+
2791+
""".strip()
2792+
+ "\n"
2793+
)
2794+
2795+
new_lines = (
2796+
"readme-renderer",
2797+
"readme-renderer",
2798+
"""
2799+
readme_renderer==25.0 \\
2800+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2801+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2802+
2803+
""".strip()
2804+
+ "\n",
2805+
)
2806+
result = hashin.amend_requirements_content(requirements, [new_lines])
2807+
assert result == requirements
2808+
2809+
def test_amend_requirements_with_env_markers_same_version(self):
2810+
requirements = (
2811+
"""
2812+
readme_renderer==25.0; python_version <= "3.4" \\
2813+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2814+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2815+
2816+
""".strip()
2817+
+ "\n"
2818+
)
2819+
2820+
new_lines = (
2821+
"readme-renderer",
2822+
"readme-renderer",
2823+
"""
2824+
readme_renderer==25.0; python_version <= "3.4" \\
2825+
--hash=sha256:1b6d8dd1673a0b293766b4106af766b6eff3654605f9c4f239e65de6076bc222 \\
2826+
--hash=sha256:e67d64242f0174a63c3b727801a2fff4c1f38ebe5d71d95ff7ece081945a6cd4
2827+
2828+
""".strip()
2829+
+ "\n",
2830+
)
2831+
result = hashin.amend_requirements_content(requirements, [new_lines])
2832+
assert result == requirements
2833+
2834+
def test_run_old_name_no_version_change(self, murlopen, tmpfile, capsys):
2835+
def mocked_get(url, **options):
2836+
if url == "https://pypi.org/pypi/readme_renderer/json":
2837+
return _Response(
2838+
{
2839+
"info": {"version": "0.25", "name": "readme-renderer"},
2840+
"releases": {
2841+
"25.0": [
2842+
{
2843+
"url": "https://pypi.org/packages/source/p/readme-renderer/readme_renderer-25.0.tar.gz",
2844+
"digests": {"sha256": "bbbbb"},
2845+
}
2846+
],
2847+
"26.0": [
2848+
{
2849+
"url": "https://pypi.org/packages/source/p/readme-renderer/readme_renderer-26.0.tar.gz",
2850+
"digests": {"sha256": "aaaaa"},
2851+
}
2852+
],
2853+
},
2854+
}
2855+
)
2856+
2857+
murlopen.side_effect = mocked_get
2858+
2859+
with tmpfile() as filename:
2860+
with open(filename, "w") as f:
2861+
f.write("readme_renderer==25.0 \\\n")
2862+
f.write(" --hash=sha256:bbbbb\n")
2863+
f.write("\n")
2864+
2865+
retcode = hashin.run("readme_renderer==25.0", filename, "sha256")
2866+
assert retcode == 0
2867+
with open(filename) as f:
2868+
output = f.read()
2869+
assert "readme_renderer==25.0" in output
2870+
2871+
def test_run_old_name_new_version_change(self, murlopen, tmpfile, capsys):
2872+
def mocked_get(url, **options):
2873+
if url == "https://pypi.org/pypi/readme_renderer/json":
2874+
return _Response(
2875+
{
2876+
"info": {"version": "0.25", "name": "readme-renderer"},
2877+
"releases": {
2878+
"25.0": [
2879+
{
2880+
"url": "https://pypi.org/packages/source/p/readme-renderer/readme_renderer-25.0.tar.gz",
2881+
"digests": {"sha256": "bbbbb"},
2882+
}
2883+
],
2884+
"26.0": [
2885+
{
2886+
"url": "https://pypi.org/packages/source/p/readme-renderer/readme_renderer-26.0.tar.gz",
2887+
"digests": {"sha256": "aaaaa"},
2888+
}
2889+
],
2890+
},
2891+
}
2892+
)
2893+
2894+
murlopen.side_effect = mocked_get
2895+
2896+
with tmpfile() as filename:
2897+
with open(filename, "w") as f:
2898+
f.write("readme_renderer==26.0 \\\n")
2899+
f.write(" --hash=sha256:bbbbb\n")
2900+
f.write("\n")
2901+
2902+
retcode = hashin.run("readme_renderer==26.0", filename, "sha256")
2903+
assert retcode == 0
2904+
with open(filename) as f:
2905+
output = f.read()
2906+
assert "readme-renderer==26.0" in output

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ python =
77
3.4: py34
88
3.5: py35
99
3.6: py36, lint, restlint
10+
3.7: py37, lint, restlint
1011

1112
[testenv]
1213
usedevelop = True

0 commit comments

Comments
 (0)