Exemplo n.º 1
0
def test_remove_youngest_descendant_nodes_with_specs():
    records, specs = get_conda_build_record_set()
    graph = PrefixGraph(records, tuple(specs) + (MatchSpec("python:requests"),))

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'ca-certificates',
        'conda-env',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'patchelf',
        'tk',
        'xz',
        'yaml',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'beautifulsoup4',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'filelock',
        'glob2',
        'idna',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pycparser',
        'pysocks',
        'pyyaml',
        'ruamel_yaml',
        'six',
        'cffi',
        'setuptools',
        'cryptography',
        'jinja2',
        'pyopenssl',
        'urllib3',
        'requests',
        'conda',
    )
    assert remaining_nodes == order

    order = (
        'intel-openmp',
        'conda-build',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order

    # again
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'conda-env',
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'patchelf',
        'tk',
        'xz',
        'yaml',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'beautifulsoup4',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'filelock',
        'glob2',
        'idna',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pycparser',
        'pysocks',
        'pyyaml',
        'ruamel_yaml',
        'six',
        'cffi',
        'setuptools',
        'cryptography',
        'jinja2',
        'pyopenssl',
        'urllib3',
        'requests',
    )
    assert remaining_nodes == order

    order = (
        'conda',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order

    # now test prune
    removed_nodes = graph.prune()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'idna',
        'pycparser',
        'pysocks',
        'six',
        'cffi',
        'cryptography',
        'pyopenssl',
        'urllib3',
        'requests',
    )
    assert remaining_nodes == order

    order = (
        'conda-env',
        'patchelf',
        'yaml',
        'beautifulsoup4',
        'filelock',
        'glob2',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pyyaml',
        'ruamel_yaml',
        'setuptools',
        'jinja2',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order
Exemplo n.º 2
0
def test_deep_cyclical_dependency():
    # Basically, the whole purpose of this test is to make sure nothing blows up with
    # recursion errors or anything like that.  Cyclical dependencies will always lead to
    # problems, and the tests here document the behavior.

    # "sqlite-3.20.1-haaaaaaa_4.tar.bz2": {
    #   "build": "haaaaaaa_4",
    #   "build_number": 4,
    #   "depends": [
    #     "libedit",
    #     "libgcc-ng >=7.2.0",
    #     "jinja2 2.9.6"
    #   ],
    #   "license": "Public-Domain (http://www.sqlite.org/copyright.html)",
    #   "md5": "deadbeefdd677bc3ed98ddd4deadbeef",
    #   "name": "sqlite",
    #   "sha256": "deadbeefabd915d2f13da177a29e264e59a0ae3c6fd2a31267dcc6a8deadbeef",
    #   "size": 1540584,
    #   "subdir": "linux-64",
    #   "timestamp": 1505666646842,
    #   "version": "3.20.1"
    # },
    graph = PrefixGraph(*get_sqlite_cyclical_record_set())

    nodes = tuple(rec.name for rec in graph.records)
    pprint(nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',  # deep cyclical dependency; guess this is what we get
    )
    assert nodes == order

    # test remove spec
    # because of this deep cyclical dependency, removing jinja2 will remove sqlite and python
    expected_removal = (
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',
    )

    removed_nodes = graph.remove_spec(MatchSpec("sqlite"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("python"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("jinja2"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("markupsafe"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        'flask',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.prune()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        'click',
        'itsdangerous',
        'werkzeug',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        # None, because of the cyclical dependency?
    )
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    markupsafe_node = graph.get_node_by_name('markupsafe')
    markupsafe_ancestors = graph.all_ancestors(markupsafe_node)
    nodes = tuple(rec.name for rec in markupsafe_ancestors)
    pprint(nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'certifi',
        'markupsafe',
        'python',
        'setuptools',
        'jinja2',
        'sqlite',
    )
    assert nodes == order

    markupsafe_descendants = graph.all_descendants(markupsafe_node)
    nodes = tuple(rec.name for rec in markupsafe_descendants)
    pprint(nodes)
    order = (
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',
    )
    assert nodes == order
Exemplo n.º 3
0
def test_deep_cyclical_dependency():
    # Basically, the whole purpose of this test is to make sure nothing blows up with
    # recursion errors or anything like that.  Cyclical dependencies will always lead to
    # problems, and the tests here document the behavior.

    # "sqlite-3.20.1-haaaaaaa_4.tar.bz2": {
    #   "build": "haaaaaaa_4",
    #   "build_number": 4,
    #   "depends": [
    #     "libedit",
    #     "libgcc-ng >=7.2.0",
    #     "jinja2 2.9.6"
    #   ],
    #   "license": "Public-Domain (http://www.sqlite.org/copyright.html)",
    #   "md5": "deadbeefdd677bc3ed98ddd4deadbeef",
    #   "name": "sqlite",
    #   "sha256": "deadbeefabd915d2f13da177a29e264e59a0ae3c6fd2a31267dcc6a8deadbeef",
    #   "size": 1540584,
    #   "subdir": "linux-64",
    #   "timestamp": 1505666646842,
    #   "version": "3.20.1"
    # },
    graph = PrefixGraph(*get_sqlite_cyclical_record_set())

    nodes = tuple(rec.name for rec in graph.records)
    pprint(nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',  # deep cyclical dependency; guess this is what we get
    )
    assert nodes == order

    # test remove spec
    # because of this deep cyclical dependency, removing jinja2 will remove sqlite and python
    expected_removal = (
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',
    )

    removed_nodes = graph.remove_spec(MatchSpec("sqlite"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("python"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("jinja2"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("markupsafe"))
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        'flask',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.prune()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        'click',
        'itsdangerous',
        'werkzeug',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    expected_removal = (
        # None, because of the cyclical dependency?
    )
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    markupsafe_node = graph.get_node_by_name('markupsafe')
    markupsafe_ancestors = graph.all_ancestors(markupsafe_node)
    nodes = tuple(rec.name for rec in markupsafe_ancestors)
    pprint(nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'certifi',
        'markupsafe',
        'python',
        'setuptools',
        'jinja2',
        'sqlite',
    )
    assert nodes == order

    markupsafe_descendants = graph.all_descendants(markupsafe_node)
    nodes = tuple(rec.name for rec in markupsafe_descendants)
    pprint(nodes)
    order = (
        'certifi',
        'click',
        'itsdangerous',
        'markupsafe',
        'python',
        'setuptools',
        'werkzeug',
        'jinja2',
        'flask',
        'sqlite',
    )
    assert nodes == order
Exemplo n.º 4
0
def post_solve_handling(context, prefix_data, final_precs, specs_to_add,
                        specs_to_remove):
    # Special case handling for various DepsModifier flags.
    if context.deps_modifier == DepsModifier.NO_DEPS:
        # In the NO_DEPS case, we need to start with the original list of packages in the
        # environment, and then only modify packages that match specs_to_add or
        # specs_to_remove.
        #
        # Help information notes that use of NO_DEPS is expected to lead to broken
        # environments.
        _no_deps_solution = IndexedSet(prefix_data.iter_records())
        only_remove_these = set(prec for spec in specs_to_remove
                                for prec in _no_deps_solution
                                if spec.match(prec))
        _no_deps_solution -= only_remove_these

        only_add_these = set(prec for spec in specs_to_add
                             for prec in final_precs if spec.match(prec))
        remove_before_adding_back = set(prec.name for prec in only_add_these)
        _no_deps_solution = IndexedSet(
            prec for prec in _no_deps_solution
            if prec.name not in remove_before_adding_back)
        _no_deps_solution |= only_add_these
        # ssc.solution_precs = _no_deps_solution
        solution_precs = _no_deps_solution

        return solution_precs, specs_to_add, specs_to_remove
    # TODO: check if solution is satisfiable, and emit warning if it's not

    elif (context.deps_modifier == DepsModifier.ONLY_DEPS
          and context.update_modifier != UpdateModifier.UPDATE_DEPS):
        # Using a special instance of PrefixGraph to remove youngest child nodes that match
        # the original specs_to_add.  It's important to remove only the *youngest* child nodes,
        # because a typical use might be `conda install --only-deps python=2 flask`, and in
        # that case we'd want to keep python.
        #
        # What are we supposed to do if flask was already in the environment?
        # We can't be removing stuff here that's already in the environment.
        #
        # What should be recorded for the user-requested specs in this case? Probably all
        # direct dependencies of flask.
        graph = PrefixGraph(final_precs, specs_to_add)
        removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
        specs_to_add = set(specs_to_add)
        specs_to_add_names = set((s.name for s in specs_to_add))

        for prec in removed_nodes:
            for dep in prec.depends:
                dep = MatchSpec(dep)
                if dep.name not in specs_to_add_names:
                    specs_to_add.add(dep)
        # unfreeze
        specs_to_add = frozenset(specs_to_add)

        # Add back packages that are already in the prefix.
        specs_to_remove_names = set(spec.name for spec in specs_to_remove)
        add_back = tuple(
            prefix_data.get(node.name, None) for node in removed_nodes
            if node.name not in specs_to_remove_names)
        solution_precs = tuple(
            PrefixGraph(concatv(graph.graph, filter(None, add_back))).graph)

        return solution_precs, specs_to_add, specs_to_remove

    return final_precs, specs_to_add, specs_to_remove
Exemplo n.º 5
0
def test_remove_youngest_descendant_nodes_with_specs():
    records, specs = get_conda_build_record_set()
    graph = PrefixGraph(records, tuple(specs) + (MatchSpec("python:requests"),))

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'ca-certificates',
        'conda-env',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'patchelf',
        'tk',
        'xz',
        'yaml',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'beautifulsoup4',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'filelock',
        'glob2',
        'idna',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pycparser',
        'pysocks',
        'pyyaml',
        'ruamel_yaml',
        'six',
        'cffi',
        'setuptools',
        'cryptography',
        'jinja2',
        'pyopenssl',
        'urllib3',
        'requests',
        'conda',
    )
    assert remaining_nodes == order

    order = (
        'intel-openmp',
        'conda-build',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order

    # again
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'conda-env',
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'patchelf',
        'tk',
        'xz',
        'yaml',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'beautifulsoup4',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'filelock',
        'glob2',
        'idna',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pycparser',
        'pysocks',
        'pyyaml',
        'ruamel_yaml',
        'six',
        'cffi',
        'setuptools',
        'cryptography',
        'jinja2',
        'pyopenssl',
        'urllib3',
        'requests',
    )
    assert remaining_nodes == order

    order = (
        'conda',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order

    # now test prune
    removed_nodes = graph.prune()

    remaining_nodes = tuple(rec.name for rec in graph.records)
    pprint(remaining_nodes)
    order = (
        'ca-certificates',
        'libgcc-ng',
        'libstdcxx-ng',
        'libffi',
        'ncurses',
        'openssl',
        'tk',
        'xz',
        'zlib',
        'libedit',
        'readline',
        'sqlite',
        'python',
        'asn1crypto',
        'certifi',
        'chardet',
        'cryptography-vectors',
        'idna',
        'pycparser',
        'pysocks',
        'six',
        'cffi',
        'cryptography',
        'pyopenssl',
        'urllib3',
        'requests',
    )
    assert remaining_nodes == order

    order = (
        'conda-env',
        'patchelf',
        'yaml',
        'beautifulsoup4',
        'filelock',
        'glob2',
        'markupsafe',
        'pkginfo',
        'psutil',
        'pycosat',
        'pyyaml',
        'ruamel_yaml',
        'setuptools',
        'jinja2',
    )
    removed_nodes = tuple(rec.name for rec in removed_nodes)
    pprint(removed_nodes)
    assert removed_nodes == order
Exemplo n.º 6
0
def test_deep_cyclical_dependency():
    # Basically, the whole purpose of this test is to make sure nothing blows up with
    # recursion errors or anything like that.  Cyclical dependencies will always lead to
    # problems, and the tests here document the behavior.

    # "sqlite-3.20.1-haaaaaaa_4.tar.bz2": {
    #   "build": "haaaaaaa_4",
    #   "build_number": 4,
    #   "depends": [
    #     "libedit",
    #     "libgcc-ng >=7.2.0",
    #     "jinja2 2.9.6"
    #   ],
    #   "license": "Public-Domain (http://www.sqlite.org/copyright.html)",
    #   "md5": "deadbeefdd677bc3ed98ddd4deadbeef",
    #   "name": "sqlite",
    #   "sha256": "deadbeefabd915d2f13da177a29e264e59a0ae3c6fd2a31267dcc6a8deadbeef",
    #   "size": 1540584,
    #   "subdir": "linux-64",
    #   "timestamp": 1505666646842,
    #   "version": "3.20.1"
    # },
    graph = PrefixGraph(*get_sqlite_cyclical_record_set())

    nodes = tuple(rec.dist_str() for rec in graph.records)
    print(nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',  # deep cyclical dependency; guess this is what we get
    )
    assert nodes == order

    # test remove spec
    # because of this deep cyclical dependency, removing jinja2 will remove sqlite and python
    expected_removal = (
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )

    removed_nodes = graph.remove_spec(MatchSpec("sqlite"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("python"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("jinja2"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("markupsafe"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = (
        'channel-4::flask-0.12.2-py36hb24657c_0',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.prune()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = (
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::werkzeug-0.14.1-py36_0',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = (
        # None, because of the cyclical dependency?
    )
    assert removed_nodes == expected_removal


    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    markupsafe_node = graph.get_node_by_name('markupsafe')
    markupsafe_ancestors = graph.all_ancestors(markupsafe_node)
    nodes = tuple(rec.dist_str() for rec in markupsafe_ancestors)
    print(nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )
    assert nodes == order

    markupsafe_descendants = graph.all_descendants(markupsafe_node)
    nodes = tuple(rec.dist_str() for rec in markupsafe_descendants)
    print(nodes)
    order = (
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )
    assert nodes == order
Exemplo n.º 7
0
def test_remove_youngest_descendant_nodes_with_specs():
    records, specs = get_conda_build_record_set()
    graph = PrefixGraph(records, tuple(specs) + (MatchSpec("requests"),))

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
        'channel-4::conda-4.4.10-py36_0',
    )
    assert remaining_nodes == order

    order = (
        'channel-4::intel-openmp-2018.0.0-hc7b2577_8',
        'channel-4::conda-build-3.5.1-py36_0',
    )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order

    # again
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
    )
    assert remaining_nodes == order

    order = (
        'channel-4::conda-4.4.10-py36_0',
    )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order

    # now test prune
    removed_nodes = graph.prune()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
    )
    assert remaining_nodes == order

    order = (
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
    )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order
Exemplo n.º 8
0
def test_deep_cyclical_dependency():
    # Basically, the whole purpose of this test is to make sure nothing blows up with
    # recursion errors or anything like that.  Cyclical dependencies will always lead to
    # problems, and the tests here document the behavior.

    # "sqlite-3.20.1-haaaaaaa_4.tar.bz2": {
    #   "build": "haaaaaaa_4",
    #   "build_number": 4,
    #   "depends": [
    #     "libedit",
    #     "libgcc-ng >=7.2.0",
    #     "jinja2 2.9.6"
    #   ],
    #   "license": "Public-Domain (http://www.sqlite.org/copyright.html)",
    #   "md5": "deadbeefdd677bc3ed98ddd4deadbeef",
    #   "name": "sqlite",
    #   "sha256": "deadbeefabd915d2f13da177a29e264e59a0ae3c6fd2a31267dcc6a8deadbeef",
    #   "size": 1540584,
    #   "subdir": "linux-64",
    #   "timestamp": 1505666646842,
    #   "version": "3.20.1"
    # },
    graph = PrefixGraph(*get_sqlite_cyclical_record_set())

    nodes = tuple(rec.dist_str() for rec in graph.records)
    print(nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',  # deep cyclical dependency; guess this is what we get
    )
    assert nodes == order

    # test remove spec
    # because of this deep cyclical dependency, removing jinja2 will remove sqlite and python
    expected_removal = (
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )

    removed_nodes = graph.remove_spec(MatchSpec("sqlite"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("python"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("jinja2"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_spec(MatchSpec("markupsafe"))
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = ('channel-4::flask-0.12.2-py36hb24657c_0', )
    assert removed_nodes == expected_removal

    removed_nodes = graph.prune()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = (
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::werkzeug-0.14.1-py36_0',
    )
    assert removed_nodes == expected_removal

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    expected_removal = (
        # None, because of the cyclical dependency?
    )
    assert removed_nodes == expected_removal

    graph = PrefixGraph(*get_sqlite_cyclical_record_set())
    markupsafe_node = graph.get_node_by_name('markupsafe')
    markupsafe_ancestors = graph.all_ancestors(markupsafe_node)
    nodes = tuple(rec.dist_str() for rec in markupsafe_ancestors)
    print(nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )
    assert nodes == order

    markupsafe_descendants = graph.all_descendants(markupsafe_node)
    nodes = tuple(rec.dist_str() for rec in markupsafe_descendants)
    print(nodes)
    order = (
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::click-6.7-py36h5253387_0',
        'channel-4::itsdangerous-0.24-py36h93cc618_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::werkzeug-0.14.1-py36_0',
        'channel-4::jinja2-2.9.6-py36h489bce4_1',
        'channel-4::flask-0.12.2-py36hb24657c_0',
        'channel-4::sqlite-3.20.1-haaaaaaa_4',
    )
    assert nodes == order
Exemplo n.º 9
0
def test_remove_youngest_descendant_nodes_with_specs():
    records, specs = get_conda_build_record_set()
    graph = PrefixGraph(records, tuple(specs) + (MatchSpec("requests"), ))

    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
        'channel-4::conda-4.4.10-py36_0',
    )
    assert remaining_nodes == order

    order = (
        'channel-4::intel-openmp-2018.0.0-hc7b2577_8',
        'channel-4::conda-build-3.5.1-py36_0',
    )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order

    # again
    removed_nodes = graph.remove_youngest_descendant_nodes_with_specs()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
    )
    assert remaining_nodes == order

    order = ('channel-4::conda-4.4.10-py36_0', )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order

    # now test prune
    removed_nodes = graph.prune()

    remaining_nodes = tuple(rec.dist_str() for rec in graph.records)
    print(remaining_nodes)
    order = (
        'channel-4::ca-certificates-2017.08.26-h1d4fec5_0',
        'channel-4::libgcc-ng-7.2.0-h7cc24e2_2',
        'channel-4::libstdcxx-ng-7.2.0-h7a57d05_2',
        'channel-4::libffi-3.2.1-hd88cf55_4',
        'channel-4::ncurses-6.0-h9df7e31_2',
        'channel-4::openssl-1.0.2n-hb7f436b_0',
        'channel-4::tk-8.6.7-hc745277_3',
        'channel-4::xz-5.2.3-h55aa19d_2',
        'channel-4::zlib-1.2.11-ha838bed_2',
        'channel-4::libedit-3.1-heed3624_0',
        'channel-4::readline-7.0-ha6073c6_4',
        'channel-4::sqlite-3.22.0-h1bed415_0',
        'channel-4::python-3.6.4-hc3d631a_1',
        'channel-4::asn1crypto-0.24.0-py36_0',
        'channel-4::certifi-2018.1.18-py36_0',
        'channel-4::chardet-3.0.4-py36h0f667ec_1',
        'channel-4::idna-2.6-py36h82fb2a8_1',
        'channel-4::pycparser-2.18-py36hf9f622e_1',
        'channel-4::pysocks-1.6.7-py36hd97a5b1_1',
        'channel-4::six-1.11.0-py36h372c433_1',
        'channel-4::cffi-1.11.4-py36h9745a5d_0',
        'channel-4::cryptography-2.1.4-py36hd09be54_0',
        'channel-4::pyopenssl-17.5.0-py36h20ba746_0',
        'channel-4::urllib3-1.22-py36hbe7ace6_0',
        'channel-4::requests-2.18.4-py36he2e5f8d_1',
    )
    assert remaining_nodes == order

    order = (
        'channel-4::conda-env-2.6.0-h36134e3_1',
        'channel-4::patchelf-0.9-hf79760b_2',
        'channel-4::yaml-0.1.7-had09818_2',
        'channel-4::beautifulsoup4-4.6.0-py36h49b8c8c_1',
        'channel-4::filelock-3.0.4-py36_0',
        'channel-4::glob2-0.6-py36he249c77_0',
        'channel-4::markupsafe-1.0-py36hd9260cd_1',
        'channel-4::pkginfo-1.4.1-py36h215d178_1',
        'channel-4::psutil-5.4.3-py36h14c3975_0',
        'channel-4::pycosat-0.6.3-py36h0a5515d_0',
        'channel-4::pyyaml-3.12-py36hafb9ca4_1',
        'channel-4::ruamel_yaml-0.15.35-py36h14c3975_1',
        'channel-4::conda-verify-2.0.0-py36h98955d8_0',
        'channel-4::setuptools-38.5.1-py36_0',
        'channel-4::jinja2-2.10-py36ha16c418_0',
    )
    removed_nodes = tuple(rec.dist_str() for rec in removed_nodes)
    print(removed_nodes)
    assert removed_nodes == order