def test_Django_sanity_test(self): """Test outdated minor and major versions of Django""" test_p = "Django" n = [x for x in self.nodes if x[0].lower() == test_p.lower()][0] p = Package(n[0], n[1]) return_info = p.check_versions() self.assertEqual(return_info['major_version']['outdated'], True) self.assertEqual(return_info['minor_version']['outdated'], True)
def test_false_package_returns_None(self): """Given nonsense package, return None""" p = Package("abcde12345GGGGGG", '0.0.0') info = p.check_versions() self.assertEqual(info['minor_version']['outdated'], None) self.assertEqual(info['minor_version']['latest'], None) self.assertEqual(info['major_version']['outdated'], None) self.assertEqual(info['major_version']['latest'], None)
def setUp(self): # Current Env: self.nodes = [('A', '1.0.0'), ('B', '1.0.0'), ('C', '1.0.0')] self.edges = [[('A', '1.0.0'), ('B', '1.0.0'), ('==', '1.0.0')], [('A', '1.0.0'), ('C', '1.0.0'), ('>=', '0.5.0')], ] self.ancestors, self.descendants = \ Package.get_direct_links_to_any_package('A', self.edges)
def test_resolve_package_list_empty_file_returns_empty_list(self): """Empty file returns []""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': []} data = "" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( Package.resolve_package_list(self.venv, kwargs), [])
def test_resolve_package_list_mixed_file_returns_Django(self): """file with "bad1, bad2 bad3 \n Django" returns ["Django"]""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': []} data = "bad1, bad2 bad3 \n Django" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( Package.resolve_package_list(self.venv, kwargs), ['Django'])
def setUp(self): self.nodes = [('A', '1.0.0'), ('B', '1.0.0'), ('C', '1.0.0')] self.edges = [ [('A', '1.0.0'), ('B', '1.0.0'), ('==', '1.0.0')], [('A', '1.0.0'), ('C', '1.0.0'), ('>=', '0.5.0')], ] self.ancestors, self.descendants = \ Package.get_direct_links_to_any_package('A', self.edges)
def test_resolve_package_list_2_packs_in_file_1_bad(self): """Check file with contents "Django, Nonsense" returns ['Django']""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': []} data = "Django, Nonsense" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( Package.resolve_package_list(self.venv, kwargs), ['Django'])
def test_resolve_package_list_two_packages_in_file(self): """file with 'Django pycrypto' returns ['Django', 'pycrypto']""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': []} data = "Django pycrypto" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( sorted(Package.resolve_package_list(self.venv, kwargs)), sorted(['Django', 'pycrypto']))
def test_resolve_package_list_bad_data_obj(self): """ Given bad data INTS, copes gracefully. """ kwargs = {'package_file': 'FakePackageFile.txt', 'packages': [type, object]} data = "2" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( Package.resolve_package_list(self.venv, kwargs), [])
def test_resolve_package_list_all_nodes_from_package_file(self): """Check all nodes return as list when given as list from file""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': []} all_nodes = [x[0] for x in self.nodes] data = " ".join(all_nodes) with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( sorted(Package.resolve_package_list(self.venv, kwargs)), sorted(all_nodes))
def test_resolve_package_list_same_package_from_file_and_cmd_line(self): """Duplicates are taken care of; Django from file and cmd returns just ['Django']""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': ['Django']} data = "Django" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( Package.resolve_package_list(self.venv, kwargs), ['Django'])
def setUp(self): super(TestAncestorDependencies, self).setUp() self.package = "fabtools" self.version = "0.19.0" self.fab_reqs = json.load( open("tests/deputils_data/fabtools_0_19_0_req.json", 'r')) self.ancestors, self.descendants = \ Package.get_direct_links_to_any_package( self.package, self.venv.edges)
def test_resolve_package_list_packages_from_file_and_cmd_line(self): """Django from cmd, pycrypt from file returns ['Django', 'pycrypt'""" kwargs = {'package_file': 'FakePackageFile.txt', 'packages': ['Django']} data = "pycrypto" # mocked file data with patch('{}.open'.format("magellan.package_utils"), mock_open(read_data=data), create=True): self.assertEqual( sorted(Package.resolve_package_list(self.venv, kwargs)), sorted(['Django', 'pycrypto']))
def run_as_pypi_patched(self, vers, curv=None): """helper fn to run and get mocked pypi responses""" if curv is None: curv = self.curv to_patch = "magellan.package_utils.Package" with patch(to_patch) as MockClass: MockClass.get_package_versions_from_pypi.return_value = vers return_info = Package.check_latest_major_minor_versions( self.curp, curv) return return_info
def setUp(self): """Augment prior setup for specific requirements""" super(TestDependencySet, self).setUp() self.package = "fabtools" self.version = "0.19.0" self.fab_reqs = json.load( open("tests/deputils_data/fabtools_0_19_0_req.json", 'r')) self.ancestors, self.descendants = \ Package.get_direct_links_to_any_package( self.package, self.venv.edges)
def test_z_fails(self): """ Z should fail with B<1 """ package = 'B' version = '0.0.1' ancestors, _ = Package.get_direct_links_to_any_package('B', self.edges) res = DepTools.check_if_ancestors_still_satisfied( package, version, ancestors, self.package_requirements) self.assertIn('z', res['conflicts'])
def magellan_setup_go_env(self, kwargs): """ Set up environment for main script.""" self.name, self.name_bit = self.vex_resolve_venv_name(self.name) self.resolve_venv_bin(kwargs['path_to_env_bin']) self.query_nodes_edges_in_venv() if not kwargs['keep_env_files']: self.remove_extant_env_files_from_disk() self.all_packages = { p[0].lower(): Package(p[0], p[1]) for p in self.nodes } if (kwargs['show_all_packages'] or kwargs['show_all_packages_and_versions']): self.show_all_packages_and_exit( kwargs['show_all_packages_and_versions'])
def setUp(self): self.nodes = [ ('A', '1.0.0'), ('B', '1.0.0'), ('C', '1.0.0'), ('X', '1.0.0'), ('Y', '1.0.0'), ('Z', '1.0.0'), ] self.edges = [[('A', '1.0.0'), ('B', '1.0.0'), ('==', '1.0.0')], [('A', '1.0.0'), ('C', '1.0.0'), ('>=', '0.5.0')], [('X', '1.0.0'), ('A', '1.0.0'), ('>=', '1.0.0')], [('Y', '1.0.0'), ('A', '1.0.0'), ('<=', '2.0.0')], [('Z', '1.0.0'), ('B', '1.0.0'), ('>=', '1.0.0')], ] self.ancestors, self.descendants = \ Package.get_direct_links_to_any_package('A', self.edges) p_r = {} # package_requirements: build from edges. for e in self.edges: print(e) project_name = e[0][0] version = e[0][1] key = project_name.lower() if key not in p_r: p_r[key] = {'project_name': project_name, 'version': version, 'requires': {}} sub_project_name = e[1][0] sub_key = sub_project_name.lower() sub_version = e[1][1] specs = e[2] p_r[key]['requires'][sub_key] = {'project_name': sub_project_name, 'version': sub_version, 'specs': [specs]} self.package_requirements = p_r
def test_check_ancestor_trace(self): fake_nodes = [('a', '1.0.0'), ('b', '2.0.0'), ('c', '1.4.0'), ('d', '2.0.0'), ('e', '1.6.0'), ('f', '210.0'), ] fake_edges = [[('root', '0.0.0'), fake_nodes[0]], [('root', '0.0.0'), fake_nodes[1]], [fake_nodes[0], fake_nodes[1]], [fake_nodes[1], fake_nodes[2]], [fake_nodes[2], fake_nodes[3]], [fake_nodes[3], fake_nodes[4]], [fake_nodes[4], fake_nodes[5]], ] f_venv = MagicMock() f_venv.nodes = fake_nodes f_venv.edges = fake_edges p = Package(fake_nodes[0][0], fake_nodes[0][1]) ret = p.ancestor_trace(f_venv) self.assertEqual(ret, {('root', '0.0.0'): 1, ('a', '1.0.0'): 0}) p2 = Package(fake_nodes[1][0], fake_nodes[1][1]) ret = p2.ancestor_trace(f_venv) self.assertEqual(ret, {('root', '0.0.0'): 1, ('b', '2.0.0'): 0, ('a', '1.0.0'): 1}) p5 = Package(fake_nodes[5][0], fake_nodes[5][1]) ret = p5.ancestor_trace(f_venv) self.assertEqual(ret, {('f', '210.0'): 0, ('e', '1.6.0'): 1, ('d', '2.0.0'): 2, ('c', '1.4.0'): 3, ('b', '2.0.0'): 4, ('a', '1.0.0'): 5, ('root', '0.0.0'): 5, })
def test_return_from_celery(self): """ancestors and descendants should match test data.""" anc, dec = Package.get_direct_links_to_any_package( 'celery', self.edges) self.assertEqual(anc, self.celery_ancestors) self.assertEqual(dec, self.celery_descendants)
def test_resolve_package_list_two_packages_one_bad(self): """Check ['Django', 'NONSENSE'] returns just Django""" kwargs = {'package_file': None, 'packages': ['Django', 'NONSENSE']} self.assertEqual( Package.resolve_package_list(self.venv, kwargs), ['Django'])
def test_get_ancestors_for_celery(self): """Celery returns correct ancestors""" p = Package('celery') self.assertEqual(p.ancestors(self.edges), self.celery_ancestors)
def detect_upgrade_conflicts(packages, venv, pretty=False): """ Detect conflicts between packages in current environment when upgrading other packages. At present this routine will look at just the immediate connections to a graph in the environment. It does this in 3 major ways: 1. DEPENDENCY SET - check_changes_in_requirements_vs_env Checks the required dependencies of new version against current environment to see additions/removals BY NAME ONLY. 2. REQUIRED VERSIONS - check_req_deps_satisfied_by_current_env For all dependencies of new version, checks to see whether they are satisfied by current environment versions. 3. ANCESTOR DEPENDENCIES - check_if_ancestors_still_satisfied For all the ancestor nodes that depend on PACKAGE, it checks whether the dependency specs are satisfied by the new version. :param list packages: List of (package, desired_version)'s :param Environment venv: virtual environment """ uc_deps = {} conflicts = {} for u in packages: package = u[0] version = u[1] p_v = "{0}_{1}".format(package, version.replace('.', '_')) uc_deps[p_v] = {} p_key = package.lower() cur_ver = venv.all_packages[p_key].version if parse_version(cur_ver) == parse_version(version): s = ("{} version {} is same as current!" .format(package, version)) print_col(s, 'red', 'black', pretty) continue if not PyPIHelper.check_package_version_on_pypi(package, version): continue uc_deps[p_v]['requirements'] = \ DepTools.get_deps_for_package_version( package, version, vex_options=MagellanConfig.vex_options) ancestors, descendants = Package.get_direct_links_to_any_package( package, venv.edges) # 1: DEPENDENCY SET - check_changes_in_requirements_vs_env uc_deps[p_v]['dependency_set'] = \ DepTools.check_changes_in_requirements_vs_env( uc_deps[p_v]['requirements'], descendants) # 2. REQUIRED VERSIONS - check_req_deps_satisfied_by_current_env uc_deps[p_v]['required_versions'] = \ DepTools.check_req_deps_satisfied_by_current_env( uc_deps[p_v]['requirements'], venv.nodes) # 3. ANCESTOR DEPENDENCIES - check_if_ancestors_still_satisfied uc_deps[p_v]['ancestor_dependencies'] = \ DepTools.check_if_ancestors_still_satisfied( package, version, ancestors, venv.package_requirements) conflicts[p_v] = {} try: conflicts[p_v]['dep_set'] = uc_deps[p_v]['dependency_set'] conflicts[p_v]['req_ver'] = \ uc_deps[p_v]['required_versions']['conflicts'] conflicts[p_v]['missing_packages'] = \ uc_deps[p_v]['required_versions']['missing'] conflicts[p_v]['anc_dep'] = \ uc_deps[p_v]['ancestor_dependencies']['conflicts'] except TypeError as e: maglog.debug("Error when attempting to assess conflicts {}" .format(e)) return conflicts, uc_deps
def test_get_descendants_for_celery(self): """Celery returns correct descendants""" p = Package('celery') self.assertEqual(p.descendants(self.edges), self.celery_descendants)
def _go(venv_name, **kwargs): """Main script of magellan program. If an environment is passed in but doesn't exist, then exit. If no environment is passed in, do analysis on current env. If packages are specified then do package specific analysis. Otherwise perform general analysis on environment. """ print_col = kwargs.get('colour') # print in colour # Environment Setup if not os.path.exists(MagellanConfig.cache_dir) and MagellanConfig.caching: MagellanConfig.setup_cache() if kwargs['list_all_versions']: for p in kwargs['list_all_versions']: print(p[0]) all_package_versions = PyPIHelper.all_package_versions_on_pypi( p[0]) pprint(natsorted(all_package_versions)) sys.exit() venv = Environment(venv_name) venv.magellan_setup_go_env(kwargs) requirements_file = kwargs.get('requirements_file') package_list = Package.resolve_package_list(venv, kwargs) packages = {p.lower(): venv.all_packages[p.lower()] for p in package_list} if kwargs['outdated']: if package_list: Package.check_outdated_packages(packages, print_col) elif requirements_file: print("Analysing requirements file for outdated packages.") Requirements.check_outdated_requirements_file( requirements_file, pretty=print_col) else: # if nothing passed in then check local env. Package.check_outdated_packages(venv.all_packages, print_col) sys.exit() if kwargs['get_dependencies']: # -D DepTools.acquire_and_display_dependencies( kwargs['get_dependencies'], print_col) if kwargs['get_ancestors']: # -A ancestor_dictionary = \ DepTools.get_ancestors_of_packages( kwargs['get_ancestors'], venv, print_col) if kwargs['get_descendants']: # -Z descendants_dictionary = \ DepTools.get_descendants_of_packages( kwargs['get_descendants'], venv, print_col) if kwargs['package_conflicts']: # -P addition_conflicts, upgrade_conflicts = \ DepTools.process_package_conflicts( kwargs['package_conflicts'], venv, print_col) if kwargs['detect_env_conflicts']: # -C cur_env_conflicts = DepTools.highlight_conflicts_in_current_env( venv.nodes, venv.package_requirements, print_col) if kwargs['compare_env_to_req_file']: # -R if not requirements_file: print("Please specify a requirements file with -r <file>") else: same, verdiff, req_only, env_only = \ Requirements.compare_req_file_to_env(requirements_file, venv) Requirements.print_req_env_comp_lists( same, verdiff, req_only, env_only, print_col)
def test_resolve_package_list_two_packages(self): """Check ['Django', 'whowhatwhere'] resolve from cmd line""" kwargs = {'package_file': None, 'packages': ['Django', 'whowhatwhere']} self.assertEqual( sorted(Package.resolve_package_list(self.venv, kwargs)), sorted(['Django', 'whowhatwhere']))
def test_simple_anc_dec_test(self): """ simply returns ancestors and descendants """ p = Package('celery', '3.0.19') anc, dec = p.get_direct_links_to_package(self.edges) self.assertEqual(anc, self.celery_ancestors) self.assertEqual(dec, self.celery_descendants)
def test_resolve_package_list_no_packages(self): """Return [] if given nothing""" kwargs = {'package_file': None, 'packages': []} self.assertEqual( Package.resolve_package_list(self.venv, kwargs), [])
def test_resolve_package_list_single_package_Django(self): """Check package "Django" is valid from command line.""" kwargs = {'package_file': None, 'packages': ['Django']} self.assertEqual( Package.resolve_package_list(self.venv, kwargs), ['Django'])
def test_returns_dict(self): p = Package("Django") at = p.ancestor_trace(self.venv) self.assertEqual(type(at), dict)
def test_empty_list_returned_from_invalid_package(self): """[],[] should be returned if package is invalid.""" anc, dec = Package.get_direct_links_to_any_package( 'NONSENSE_PACKAGE', self.edges) self.assertEqual(anc, []) self.assertEqual(dec, [])
def test_resolve_package_list_two_packages_all_bad(self): """Check ['bad1', 'bad2'] return []""" kwargs = {'package_file': None, 'packages': ['bad1', 'bad2']} self.assertEqual( Package.resolve_package_list(self.venv, kwargs), [])