Skip to content

Commit

Permalink
Fix #6 use sha1 instead of hash function result
Browse files Browse the repository at this point in the history
Problem
-------
Plug-in fails to read value from .previous file as its format has changed.
In the version before 0.2.1 the file contained requirements file copy. Now it
keeps integer value, result of 'hash' function on serialized set of parsed
requirements.

Solution
--------
Use SHA1 to describe unique set of the requirements. This function is more
reliable than Python 'hash' function. 'hash' function may produce different
values for the same input as it depends on a seed or depends on PYTHONHASHSEED
value.
Side-effect of using SHA1 that even if file is in the old format it will be just
rewritten with a new hash value and environment is rebuilt.

Testing
-------
Updated existing test-case to ensure that SHA1 is saved in the .previous file.
  • Loading branch information
Volodymyr Vitvitskyi committed Apr 28, 2017
1 parent 8a814b5 commit 3dff32a
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -2,7 +2,7 @@ run-tests:
tox -- py.test --pep8 tests

run-tests-continuously:
tox -e py35 -- py.test -vv --pep8 --looponfail tests
tox -e py35 -- py.test --last-failed -vv --pep8 --looponfail tests

upload-to-pypi:
python setup.py sdist bdist_wheel upload
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -11,7 +11,7 @@ def content_of(fpath):
description='Additional functionality for tox',
long_description=content_of("README.rst"),
license='http://opensource.org/licenses/MIT',
version='0.3',
version='0.4',
author='Volodymyr Vitvitskyi',
author_email='contact.volodymyr@gmail.com',
url='https://github.com/signalpillar/tox-battery',
Expand Down
23 changes: 17 additions & 6 deletions tests/test_requirements.py
Expand Up @@ -50,12 +50,12 @@ def test_venv_recreated_with_simple_changes_in_file(tmpdir):
textwrap.dedent('''
pep8
pytest-xdist==1.13.0
# ^ dependency for testing
'''))
run('tox -e python -- python -V'.split(), tmpdir)

# verify
assert not os.path.isfile(marker_fpath)
# assert True


def test_venv_notrecreated_without_requirements_file_update(tmpdir):
Expand All @@ -76,7 +76,7 @@ def test_venv_notrecreated_without_requirements_file_update(tmpdir):
[tox]
skipsdist=True
[testenv:python]
[testenv:testenvname]
deps = -rreq1/requirements.txt
commands = {posargs}
'''))
Expand All @@ -86,15 +86,20 @@ def test_venv_notrecreated_without_requirements_file_update(tmpdir):
pytest-xdist==1.13.0
pep8
'''))
run('tox -e python -- python -V'.split(), tmpdir)
run('tox -e testenvname -- python -V'.split(), tmpdir)
marker_fpath = path('.tox/python/marker.file')
update_file(marker_fpath, '')

# excercise
# nothing chnaged in the file
run('tox -e python -- python -V'.split(), tmpdir)
run('tox -e testenvname -- python -V'.split(), tmpdir)

# verify that marker file exists as we didn't recreate environment
# verify
previous_state_hash_file = path('.tox/req1-requirements.txt.testenvname.previous')
# Ensure file with current requirements saved as a hash.
assert os.path.isfile(previous_state_hash_file)
assert read_text_file(previous_state_hash_file) == 'fe75072a8b7548c8ef6a18ecfae1506c16c90ba3'
# Verify that marker file exists as we didn't recreate environment.
assert os.path.isfile(marker_fpath)


Expand Down Expand Up @@ -154,7 +159,8 @@ def test_venv_recreated_on_nested_requirements_file_update(tmpdir):


def test_venv_not_recreated_when_nested_requirements_file_do_not_change(tmpdir):
"""Ensures the venvs do not get recreated when nothing changes in the nested rquirements files."""
"""Ensures the venvs do not get recreated when nothing changes in the nested rquirements files.
"""
# given
tmpdir = tmpdir.strpath
path = lambda *args: os.path.join(tmpdir, *args)
Expand Down Expand Up @@ -209,3 +215,8 @@ def update_file(fpath, content):
os.makedirs(fdir)
with open(fpath, 'w') as fd:
fd.write(content)


def read_text_file(fpath):
with open(fpath, 'r') as fd:
return fd.read()
8 changes: 4 additions & 4 deletions toxbat/requirements.py
Expand Up @@ -20,6 +20,7 @@

# std
import filecmp
import hashlib
import os
import shutil

Expand Down Expand Up @@ -98,21 +99,20 @@ def is_changed(fpath, prev_version_fpath):
new_requirements = parse_pip_requirements(fpath)

# Hash them.
new_requirements_hash = hash(str(new_requirements))
new_requirements_hash = hashlib.sha1(str(new_requirements).encode('utf-8')).hexdigest()

# Read the hash of the previous requirements if any.
previous_requirements_hash = 0
if os.path.exists(prev_version_fpath):
with open(prev_version_fpath) as fd:
content = fd.read()
previous_requirements_hash = int(content)
previous_requirements_hash = fd.read()

# Create/Update the file with the hash of the new requirements.
dirname = os.path.dirname(prev_version_fpath)
if not os.path.isdir(dirname):
os.makedirs(dirname)
with open(prev_version_fpath, 'w+') as fd:
fd.write(str(new_requirements_hash))
fd.write(new_requirements_hash)

# Compare the hash of the new requirements with the hash of the previous requirements.
return previous_requirements_hash != new_requirements_hash
Expand Down

0 comments on commit 3dff32a

Please sign in to comment.