Skip to content

Commit

Permalink
bears/python: Add RequirementsCheckBear
Browse files Browse the repository at this point in the history
Closes #1113
  • Loading branch information
bkhanale committed Aug 4, 2019
1 parent 28fdbc6 commit 4400a84
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 0 deletions.
4 changes: 4 additions & 0 deletions bear-languages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ RadonBear:
- Python
- Python 2
- Python 3
RequirementsCheckBear:
- Python 2 Requirements
- Python 3 Requirements
- Python Requirements
RuboCopBear:
- Ruby
RubyFastererBear:
Expand Down
1 change: 1 addition & 0 deletions bear-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ munkres~=1.1.2
mypy==0.590
nbformat~=4.1
nltk~=3.2
pip-tools~=3.8.0
proselint~=0.7.0
pycodestyle~=2.2
pydocstyle~=2.0
Expand Down
2 changes: 2 additions & 0 deletions bear-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pip_requirements:
version: ~=4.1
nltk:
version: ~=3.2
pip-tools:
version: ~=3.8.0
proselint:
version: ~=0.7.0
pycodestyle:
Expand Down
60 changes: 60 additions & 0 deletions bears/python/requirements/RequirementsCheckBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import os.path

from coalib.bears.GlobalBear import GlobalBear
from coalib.results.Result import Result, RESULT_SEVERITY
from sarge import capture_both

from dependency_management.requirements.PipRequirement import PipRequirement


class RequirementsCheckBear(GlobalBear):
"""
The bear to check and find any conflicting pip dependencies.
"""
LANGUAGES = {
'Python Requirements',
'Python 2 Requirements',
'Python 3 Requirements',
}
REQUIREMENTS = {PipRequirement('pip-tools', '3.8.0')}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
LICENSE = 'AGPL-3.0'

def run(self, require_files: tuple):
"""
:param require_files:
Tuple of requirements files.
"""
data = ''
orig_file = ''

for require_file in require_files:
if not os.path.isfile(os.path.abspath(require_file)):
raise ValueError('The file \'{}\' doesn\'t exist.'
.format(require_file))

with open(require_file) as _file:
content = _file.read()
if not orig_file:
orig_file = content
else:
data += content

with open(require_files[0], 'a+') as temp_file:
temp_file.write(data)

out = capture_both('pip-compile {} -r -n --no-annotate --no-header '
'--no-index --allow-unsafe'.format(require_files[0]))

if out.stderr.text and not out.stdout.text:
pip_warning = 'Cache entry deserialization failed, entry ignored'
lines = out.stderr.text.splitlines()
lines = [line for line in lines if line not in pip_warning]
yield Result(self,
message=lines[0],
severity=RESULT_SEVERITY.MAJOR,
)

with open(require_files[0], 'w+') as _file:
_file.write(orig_file)
71 changes: 71 additions & 0 deletions tests/python/requirements/RequirementsCheckBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import os
import unittest

from queue import Queue

from bears.python.requirements.RequirementsCheckBear import (
RequirementsCheckBear)
from coalib.results.Result import Result, RESULT_SEVERITY
from coalib.settings.Section import Section
from coalib.settings.Setting import Setting


def get_absolute_test_path(file):
return os.path.join(os.path.dirname(__file__),
'requirements_test_files', file)


def read_file(file):
with open(file) as _file:
return _file.read()


class RequirementsCheckBearTest(unittest.TestCase):

def setUp(self):
self.section = Section('')
self.file_dict = {}
self.queue = Queue()
self.test_files = [get_absolute_test_path('conflict.txt'),
get_absolute_test_path('valid.txt')]
self.files = [read_file(_file) for _file in self.test_files]

def test_conflicted_file(self):
self.section.append(Setting('require_files', self.test_files[0]))
self.uut = RequirementsCheckBear({}, self.section, self.queue)
result = list(self.uut.run_bear_from_section([], {}))
self.assertEqual(result[0],
Result(origin='RequirementsCheckBear',
message=('Could not find a version that '
'matches six<=1.11.0,==1.12.0'),
severity=RESULT_SEVERITY.MAJOR))
self.assertEqual(read_file(self.test_files[0]), self.files[0])

def test_valid_file(self):
self.section.append(Setting('require_files', self.test_files[1]))
self.uut = RequirementsCheckBear({}, self.section, self.queue)
result = list(self.uut.run_bear_from_section([], {}))
self.assertEqual(result, [])
self.assertEqual(read_file(self.test_files[1]), self.files[1])

def test_multiple_require_files(self):
self.section.append(Setting('require_files',
','.join(file for file in self.test_files)))
self.uut = RequirementsCheckBear({}, self.section, self.queue)
result = list(self.uut.run_bear_from_section([], {}))
self.assertEqual(result[0],
Result(origin='RequirementsCheckBear',
message=('Could not find a version that '
'matches six<=1.11.0,==1.12.0'),
severity=RESULT_SEVERITY.MAJOR))
self.assertEqual(read_file(self.test_files[0]), self.files[0])
self.assertEqual(read_file(self.test_files[1]), self.files[1])

def test_no_existing_file(self):
invalid_test_file_path = get_absolute_test_path('invalid.txt')
self.section.append(Setting('require_files', invalid_test_file_path))
self.uut = RequirementsCheckBear({}, self.section, self.queue)
error = ('The file \'{}\' doesn\'t exist.'
.format(invalid_test_file_path))
with self.assertRaisesRegex(ValueError, error):
list(self.uut.run_bear_from_section([], {}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
six==1.12.0
six<=1.11.0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest~=3.6.4

0 comments on commit 4400a84

Please sign in to comment.