# Buggy code
def display_actions(actions, index, show_channel_urls=None):
    if show_channel_urls is None:
        show_channel_urls = config_show_channel_urls

    def channel_str(rec):
        if "schannel" in rec:
            return rec["schannel"]
        if "url" in rec:
            return url_channel(rec["url"])[1]
        if "channel" in rec:
            return canonical_channel_name(rec["channel"])
        return "<unknown>"

    def channel_filt(s):
        if show_channel_urls is False:
            return ""
        if show_channel_urls is None and s == "defaults":
            return ""
        return s

    if actions.get(inst.FETCH):
        print("\nThe following packages will be downloaded:\n")

        disp_lst = []
        for dist in actions[inst.FETCH]:
            info = index[dist + ".tar.bz2"]
            extra = "%15s" % human_bytes(info["size"])
            schannel = channel_filt(channel_str(info))
            if schannel:
                extra += "  " + schannel
            disp_lst.append((dist, extra))
        print_dists(disp_lst)

        if index and len(actions[inst.FETCH]) > 1:
            num_bytes = sum(
                index[dist + ".tar.bz2"]["size"] for dist in actions[inst.FETCH]
            )
            print(" " * 4 + "-" * 60)
            print(" " * 43 + "Total: %14s" % human_bytes(num_bytes))

    # package -> [oldver-oldbuild, newver-newbuild]
    packages = defaultdict(lambda: list(("", "")))
    features = defaultdict(lambda: list(("", "")))
    channels = defaultdict(lambda: list(("", "")))
    records = defaultdict(lambda: list((None, None)))
    linktypes = {}

    for arg in actions.get(inst.LINK, []):
        dist, lt, shortcuts = inst.split_linkarg(arg)
        fkey = dist + ".tar.bz2"
        rec = index[fkey]
        pkg = rec["name"]
        channels[pkg][1] = channel_str(rec)
        packages[pkg][1] = rec["version"] + "-" + rec["build"]
        records[pkg][1] = Package(fkey, rec)
        linktypes[pkg] = lt
        features[pkg][1] = rec.get("features", "")
    for arg in actions.get(inst.UNLINK, []):
        dist, lt, shortcuts = inst.split_linkarg(arg)
        fkey = dist + ".tar.bz2"
        rec = index.get(fkey)
        if rec is None:
            pkg, ver, build, schannel = dist2quad(dist)
            rec = dict(
                name=pkg,
                version=ver,
                build=build,
                channel=None,
                schannel="<unknown>",
                build_number=int(build) if build.isdigit() else 0,
            )
        pkg = rec["name"]
        channels[pkg][0] = channel_str(rec)
        packages[pkg][0] = rec["version"] + "-" + rec["build"]
        records[pkg][0] = Package(fkey, rec)
        features[pkg][0] = rec.get("features", "")

    #                     Put a minimum length here---.    .--For the :
    #                                                 v    v

    new = {p for p in packages if not packages[p][0]}
    removed = {p for p in packages if not packages[p][1]}
    # New packages are actually listed in the left-hand column,
    # so let's move them over there
    for pkg in new:
        for var in (packages, features, channels, records):
            var[pkg] = var[pkg][::-1]

    if packages:
        maxpkg = max(len(p) for p in packages) + 1
        maxoldver = max(len(p[0]) for p in packages.values())
        maxnewver = max(len(p[1]) for p in packages.values())
        maxoldfeatures = max(len(p[0]) for p in features.values())
        maxnewfeatures = max(len(p[1]) for p in features.values())
        maxoldchannels = max(len(channel_filt(p[0])) for p in channels.values())
        maxnewchannels = max(len(channel_filt(p[1])) for p in channels.values())
    updated = set()
    downgraded = set()
    channeled = set()
    oldfmt = {}
    newfmt = {}
    for pkg in packages:
        # That's right. I'm using old-style string formatting to generate a
        # string with new-style string formatting.
        oldfmt[pkg] = "{pkg:<%s} {vers[0]:<%s}" % (maxpkg, maxoldver)
        if maxoldchannels:
            oldfmt[pkg] += " {channels[0]:<%s}" % maxoldchannels
        if features[pkg][0]:
            oldfmt[pkg] += " [{features[0]:<%s}]" % maxoldfeatures

        lt = linktypes.get(pkg, LINK_HARD)
        lt = "" if lt == LINK_HARD else (" (%s)" % link_name_map[lt])
        if pkg in removed or pkg in new:
            oldfmt[pkg] += lt
            continue

        newfmt[pkg] = "{vers[1]:<%s}" % maxnewver
        if maxnewchannels:
            newfmt[pkg] += " {channels[1]:<%s}" % maxnewchannels
        if features[pkg][1]:
            newfmt[pkg] += " [{features[1]:<%s}]" % maxnewfeatures
        newfmt[pkg] += lt

        P0 = records[pkg][0]
        P1 = records[pkg][1]
        pri0 = P0.priority
        pri1 = P1.priority
        if pri0 is None or pri1 is None:
            pri0 = pri1 = 1
        try:
            if str(P1.version) == "custom":
                newver = str(P0.version) != "custom"
                oldver = not newver
            else:
                # <= here means that unchanged packages will be put in updated
                newver = P0.norm_version < P1.norm_version
                oldver = P0.norm_version > P1.norm_version
        except TypeError:
            newver = P0.version < P1.version
            oldver = P0.version > P1.version
        oldbld = P0.build_number > P1.build_number
        newbld = P0.build_number < P1.build_number
        if channel_priority and pri1 < pri0 and (oldver or not newver and not newbld):
            channeled.add(pkg)
        elif newver:
            updated.add(pkg)
        elif pri1 < pri0 and (oldver or not newver and oldbld):
            channeled.add(pkg)
        elif oldver:
            downgraded.add(pkg)
        elif not oldbld:
            updated.add(pkg)
        else:
            downgraded.add(pkg)

    arrow = " --> "
    lead = " " * 4

    def format(s, pkg):
        chans = [channel_filt(c) for c in channels[pkg]]
        return lead + s.format(
            pkg=pkg + ":", vers=packages[pkg], channels=chans, features=features[pkg]
        )

    if new:
        print("\nThe following NEW packages will be INSTALLED:\n")
    for pkg in sorted(new):
        # New packages have been moved to the "old" column for display
        print(format(oldfmt[pkg], pkg))

    if removed:
        print("\nThe following packages will be REMOVED:\n")
        for pkg in sorted(removed):
            print(format(oldfmt[pkg], pkg))

    if updated:
        print("\nThe following packages will be UPDATED:\n")
        for pkg in sorted(updated):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    if channeled:
        print(
            "\nThe following packages will be SUPERCEDED by a higher-priority channel:\n"
        )
        for pkg in sorted(channeled):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    if downgraded:
        print(
            "\nThe following packages will be DOWNGRADED due to dependency conflicts:\n"
        )
        for pkg in sorted(downgraded):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    print()


# Traceback (TypeError)
% conda create -p ~/anaclone --clone root
Source:      /Users/ijstokes/anaconda
Destination: /Users/ijstokes/anaclone
The following packages cannot be cloned out of the root environment:
- conda-4.1.1-py27_0
- conda-build-1.20.3-py27_0
Packages: 332
Files: 16134
An unexpected error has occurred, please consider sending the
following traceback to the conda GitHub issue tracker at:

https://github.com/conda/conda/issues

clude the output of the command 'conda info' in your report.


Traceback (most recent call last):
File "/Users/ijstokes/anaconda/envs/ana40py35/bin/conda", line 6, in <module>
sys.exit(main())
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/cli/main.py", line 120, in main
args_func(args, p)
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/cli/main.py", line 127, in args_func
args.func(args, p)
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/cli/main_create.py", line 57, in execute
install(args, parser, 'create')
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/cli/install.py", line 218, in install
'unknown': args.unknown})
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/cli/install.py", line 87, in clone
fetch_args=fetch_args)
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/misc.py", line 353, in clone_env
force_extract=False, fetch_args=fetch_args)
File "/Users/ijstokes/anaconda/lib/python2.7/site-packages/conda/misc.py", line 56, in explicit
m = url_pat.match(spec)
TypeError: expected string or buffer

# Fixed code
def display_actions(actions, index, show_channel_urls=None):
    if show_channel_urls is None:
        show_channel_urls = config_show_channel_urls

    def channel_str(rec):
        if rec.get("schannel"):
            return rec["schannel"]
        if rec.get("url"):
            return url_channel(rec["url"])[1]
        if rec.get("channel"):
            return canonical_channel_name(rec["channel"])
        return "<unknown>"

    def channel_filt(s):
        if show_channel_urls is False:
            return ""
        if show_channel_urls is None and s == "defaults":
            return ""
        return s

    if actions.get(inst.FETCH):
        print("\nThe following packages will be downloaded:\n")

        disp_lst = []
        for dist in actions[inst.FETCH]:
            info = index[dist + ".tar.bz2"]
            extra = "%15s" % human_bytes(info["size"])
            schannel = channel_filt(channel_str(info))
            if schannel:
                extra += "  " + schannel
            disp_lst.append((dist, extra))
        print_dists(disp_lst)

        if index and len(actions[inst.FETCH]) > 1:
            num_bytes = sum(
                index[dist + ".tar.bz2"]["size"] for dist in actions[inst.FETCH]
            )
            print(" " * 4 + "-" * 60)
            print(" " * 43 + "Total: %14s" % human_bytes(num_bytes))

    # package -> [oldver-oldbuild, newver-newbuild]
    packages = defaultdict(lambda: list(("", "")))
    features = defaultdict(lambda: list(("", "")))
    channels = defaultdict(lambda: list(("", "")))
    records = defaultdict(lambda: list((None, None)))
    linktypes = {}

    for arg in actions.get(inst.LINK, []):
        dist, lt, shortcuts = inst.split_linkarg(arg)
        fkey = dist + ".tar.bz2"
        rec = index[fkey]
        pkg = rec["name"]
        channels[pkg][1] = channel_str(rec)
        packages[pkg][1] = rec["version"] + "-" + rec["build"]
        records[pkg][1] = Package(fkey, rec)
        linktypes[pkg] = lt
        features[pkg][1] = rec.get("features", "")
    for arg in actions.get(inst.UNLINK, []):
        dist, lt, shortcuts = inst.split_linkarg(arg)
        fkey = dist + ".tar.bz2"
        rec = index.get(fkey)
        if rec is None:
            pkg, ver, build, schannel = dist2quad(dist)
            rec = dict(
                name=pkg,
                version=ver,
                build=build,
                channel=None,
                schannel="<unknown>",
                build_number=int(build) if build.isdigit() else 0,
            )
        pkg = rec["name"]
        channels[pkg][0] = channel_str(rec)
        packages[pkg][0] = rec["version"] + "-" + rec["build"]
        records[pkg][0] = Package(fkey, rec)
        features[pkg][0] = rec.get("features", "")

    #                     Put a minimum length here---.    .--For the :
    #                                                 v    v

    new = {p for p in packages if not packages[p][0]}
    removed = {p for p in packages if not packages[p][1]}
    # New packages are actually listed in the left-hand column,
    # so let's move them over there
    for pkg in new:
        for var in (packages, features, channels, records):
            var[pkg] = var[pkg][::-1]

    if packages:
        maxpkg = max(len(p) for p in packages) + 1
        maxoldver = max(len(p[0]) for p in packages.values())
        maxnewver = max(len(p[1]) for p in packages.values())
        maxoldfeatures = max(len(p[0]) for p in features.values())
        maxnewfeatures = max(len(p[1]) for p in features.values())
        maxoldchannels = max(len(channel_filt(p[0])) for p in channels.values())
        maxnewchannels = max(len(channel_filt(p[1])) for p in channels.values())
    updated = set()
    downgraded = set()
    channeled = set()
    oldfmt = {}
    newfmt = {}
    for pkg in packages:
        # That's right. I'm using old-style string formatting to generate a
        # string with new-style string formatting.
        oldfmt[pkg] = "{pkg:<%s} {vers[0]:<%s}" % (maxpkg, maxoldver)
        if maxoldchannels:
            oldfmt[pkg] += " {channels[0]:<%s}" % maxoldchannels
        if features[pkg][0]:
            oldfmt[pkg] += " [{features[0]:<%s}]" % maxoldfeatures

        lt = linktypes.get(pkg, LINK_HARD)
        lt = "" if lt == LINK_HARD else (" (%s)" % link_name_map[lt])
        if pkg in removed or pkg in new:
            oldfmt[pkg] += lt
            continue

        newfmt[pkg] = "{vers[1]:<%s}" % maxnewver
        if maxnewchannels:
            newfmt[pkg] += " {channels[1]:<%s}" % maxnewchannels
        if features[pkg][1]:
            newfmt[pkg] += " [{features[1]:<%s}]" % maxnewfeatures
        newfmt[pkg] += lt

        P0 = records[pkg][0]
        P1 = records[pkg][1]
        pri0 = P0.priority
        pri1 = P1.priority
        if pri0 is None or pri1 is None:
            pri0 = pri1 = 1
        try:
            if str(P1.version) == "custom":
                newver = str(P0.version) != "custom"
                oldver = not newver
            else:
                # <= here means that unchanged packages will be put in updated
                newver = P0.norm_version < P1.norm_version
                oldver = P0.norm_version > P1.norm_version
        except TypeError:
            newver = P0.version < P1.version
            oldver = P0.version > P1.version
        oldbld = P0.build_number > P1.build_number
        newbld = P0.build_number < P1.build_number
        if channel_priority and pri1 < pri0 and (oldver or not newver and not newbld):
            channeled.add(pkg)
        elif newver:
            updated.add(pkg)
        elif pri1 < pri0 and (oldver or not newver and oldbld):
            channeled.add(pkg)
        elif oldver:
            downgraded.add(pkg)
        elif not oldbld:
            updated.add(pkg)
        else:
            downgraded.add(pkg)

    arrow = " --> "
    lead = " " * 4

    def format(s, pkg):
        chans = [channel_filt(c) for c in channels[pkg]]
        return lead + s.format(
            pkg=pkg + ":", vers=packages[pkg], channels=chans, features=features[pkg]
        )

    if new:
        print("\nThe following NEW packages will be INSTALLED:\n")
    for pkg in sorted(new):
        # New packages have been moved to the "old" column for display
        print(format(oldfmt[pkg], pkg))

    if removed:
        print("\nThe following packages will be REMOVED:\n")
        for pkg in sorted(removed):
            print(format(oldfmt[pkg], pkg))

    if updated:
        print("\nThe following packages will be UPDATED:\n")
        for pkg in sorted(updated):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    if channeled:
        print(
            "\nThe following packages will be SUPERCEDED by a higher-priority channel:\n"
        )
        for pkg in sorted(channeled):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    if downgraded:
        print(
            "\nThe following packages will be DOWNGRADED due to dependency conflicts:\n"
        )
        for pkg in sorted(downgraded):
            print(format(oldfmt[pkg] + arrow + newfmt[pkg], pkg))

    print()