def parse_req_file(req_file, verbatim=False): """Take a file and return a dict of (requirement, versions) based on the files requirements specs. TODO support pip's --index-url and --find-links requirements lines. TODO support Git, Subversion, Bazaar, Mercurial requirements lines. """ req_list = [] requirements = req_file.readlines() for requirement in requirements: requirement_no_comments = requirement.split('#')[0].strip() # if matching requirement line (Thing==1.2.3), update dict, continue req_match = re.match('\s*(?P<package>\S+)==(?P<version>\S+)', requirement_no_comments) if req_match: req_list.append((req_match.group('package'), req_match.group('version'))) elif requirement_no_comments.startswith('-r'): base_dir = os.path.dirname(os.path.abspath(req_file.name)) file_name = requirement_no_comments.split(' ')[1] new_path = os.path.join(base_dir, file_name) try: if verbatim: req_list.append((None, requirement)) req_list.extend(parse_req_file(open(new_path), verbatim=verbatim)) except IOError: print('Failed to import {}'.format(file_name)) elif verbatim: req_list.append((None, requirement)) return req_list
def test_recursive_requirements_file_verbatim(self): with open( os.path.join(os.path.dirname(__file__), 'files/_develop.txt') ) as f: d = parse_req_file(f, verbatim=True) comments = [x[1] for x in d if not x[0]] self.assertTrue('# Development Requirements\n' in comments)
def test_requirements_file(self): with open( os.path.join(os.path.dirname(__file__), 'files/_develop.txt') ) as f: d = parse_req_file(f, verbatim=False) self.assertTrue(d[0][0] == 'ipython') self.assertTrue(d[0][1] == '1.1.0')
def main(req_files=[], verbose=False, outdated=False, latest=False, verbatim=False, print_only=False): """ Process a list of requirements to determine how out of date they are. """ requirements = [] for req_file in req_files: requirements.extend(parse_req_file(req_file, verbatim=verbatim)) req_file.close() total_time_delta = 0 if USE_PIPROT_IO: only_requirements = {} for req, version in requirements: if req: only_requirements[req] = version release_data = bulk_get_version_and_release_dates(only_requirements) else: release_data = None for req, version in requirements: if print_only: if req: print("{}=={}".format(req, version)) else: print(version) elif verbatim and not req: sys.stdout.write(version) elif req: latest_version, latest_release_date = get_version_and_release_date(req, verbose=verbose, release_data=release_data) specified_version, specified_release_date = get_version_and_release_date(req, version, verbose=verbose, release_data=release_data) if latest_release_date and specified_release_date: time_delta = (latest_release_date - specified_release_date).days total_time_delta = total_time_delta + time_delta if verbose: if time_delta > 0: print('{} ({}) is {} days out of date. Latest is {}'.format(req, version, time_delta, latest_version)) elif not outdated: print('{} ({}) is up to date'.format(req, version)) if latest and latest_version != specified_version: print('{}=={} # Updated from {}'.format(req, latest_version, specified_version)) elif verbatim and latest_version != specified_version: print('{}=={} # Latest {}'.format(req, specified_version, latest_version)) elif verbatim: print('{}=={}'.format(req, specified_version)) elif verbatim: print('{}=={} # Error checking latest version'.format(req, version)) if verbatim: verbatim = "# Generated with piprot {}\n# ".format(VERSION) else: verbatim = "" if total_time_delta > 0: print("{}Your requirements are {} days out of date".format(verbatim, total_time_delta)) else: print("{}Looks like you've been keeping up to date, time for a delicious beverage!".format(verbatim))
def test_recursive_requirements_length(self): with open( os.path.join( os.path.dirname(__file__), 'files/test-requirements.txt' ) ) as f: d = parse_req_file(f, verbatim=False) self.assertEqual(len(d), 3)
def test_recursive_requirements_file(self): with open( os.path.join( os.path.dirname(__file__), 'files/test-requirements.txt' ) ) as f: d = parse_req_file(f, verbatim=False) reqs = [x[0] for x in d] self.assertTrue('ipython' in reqs)
def test_full_github_requirements_test(self): url = build_github_url('sesh/piprot', path='requirements.txt') expected = 'https://raw.githubusercontent.com/sesh/piprot/master/requirements.txt' self.assertEqual(url, expected) response = requests.get(url) req_file = StringIO(response.text) requirements = parse_req_file(req_file) self.assertTrue('requests' in [req for req, version in requirements])
def test_full_github_requirements_test(self): url = build_github_url("sesh/piprot", path="requirements.txt") expected = "https://raw.githubusercontent.com/sesh/piprot/master/requirements.txt" # noqa self.assertEqual(url, expected) response = requests.get(url) req_file = StringIO(response.text) requirements = parse_req_file(req_file) self.assertTrue("requests" in [req for req, version in requirements])
def test_ignore_in_requirements_file(self): with open( os.path.join( os.path.dirname(__file__), 'files/test-requirements.txt' ) ) as f: d = parse_req_file(f, verbatim=False) ignored = [x[0] for x in d if x[2]] self.assertTrue('piprot' in ignored)
def test_requirements_length(self): d = parse_req_file(open(os.path.join(os.path.dirname(__file__), 'files/_develop.txt')), verbatim=False) self.assertEqual(len(d), 1)
def test_requirement_exact(self): f = StringIO("requests==1.2.3") d = parse_req_file(f) self.assertTrue(d[0][0] == 'requests') self.assertTrue(d[0][1] == '1.2.3')
def test_requirements_with_extra(self): f = StringIO("requests[security]==1.2.3") d = parse_req_file(f) self.assertEqual(d[0][0], 'requests') self.assertEqual(d[0][1], '1.2.3')
def test_requirements_ignore(self): f = StringIO("requests==1.2.3 # norot") d = parse_req_file(f) self.assertEqual(d[0][0], 'requests') self.assertEqual(d[0][1], '1.2.3') self.assertEqual(d[0][2], True)
def test_requirements_with_extra(self): f = StringIO("requests[security]==1.2.3") d = parse_req_file(f) self.assertEqual(d[0][0], 'requests') self.assertEqual(d[0][1], '1.2.3')