diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index f576a527981..2e35d6e6689 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -35,6 +35,7 @@ requirements: run: - python - conda-package-handling >=1.3.0 + - cytoolz >=0.8.1 - menuinst >=1.4.11,<2 # [win] - pycosat >=0.6.3 - pyopenssl >=16.2.0 @@ -45,7 +46,6 @@ requirements: - conda-build >=3 - conda-env >=2.6 - conda-content-trust >=0.1.1 - - cytoolz >=0.8.1 test: source_files: diff --git a/conda/_vendor/toolz/LICENSE.txt b/conda/_vendor/toolz/LICENSE.txt deleted file mode 100644 index eeb91b202ca..00000000000 --- a/conda/_vendor/toolz/LICENSE.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2013 Matthew Rocklin - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - a. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - b. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - c. Neither the name of toolz nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. diff --git a/conda/_vendor/toolz/__init__.py b/conda/_vendor/toolz/__init__.py deleted file mode 100644 index 3a7d1e3580b..00000000000 --- a/conda/_vendor/toolz/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -try: - from cytoolz import __version__ as cytoolz_version - if tuple(int(x) for x in cytoolz_version.split(".")) < (0, 8, 2): - raise ImportError() - from cytoolz.itertoolz import * - from cytoolz.dicttoolz import * - from cytoolz.functoolz import excepts -except (ImportError, ValueError): - from .itertoolz import * - from .dicttoolz import * - - # Importing from toolz.functoolz is slow since it imports inspect. - # Copy the relevant part of excepts' implementation instead: - class excepts(object): - def __init__(self, exc, func, handler=lambda exc: None): - self.exc = exc - self.func = func - self.handler = handler - - def __call__(self, *args, **kwargs): - try: - return self.func(*args, **kwargs) - except self.exc as e: - return self.handler(e) - -__version__ = '0.9.0' diff --git a/conda/_vendor/toolz/compatibility.py b/conda/_vendor/toolz/compatibility.py deleted file mode 100644 index 67635026055..00000000000 --- a/conda/_vendor/toolz/compatibility.py +++ /dev/null @@ -1,40 +0,0 @@ -import operator -import sys -PY3 = sys.version_info[0] > 2 -PY33 = sys.version_info[0] == 3 and sys.version_info[1] == 3 -PY34 = sys.version_info[0] == 3 and sys.version_info[1] == 4 -PYPY = hasattr(sys, 'pypy_version_info') - -__all__ = ('map', 'filter', 'range', 'zip', 'reduce', 'zip_longest', - 'iteritems', 'iterkeys', 'itervalues', 'filterfalse', - 'PY3', 'PY34', 'PYPY', 'import_module') - -if PY3: - map = map - filter = filter - range = range - zip = zip - from functools import reduce - from itertools import zip_longest - from itertools import filterfalse - iteritems = operator.methodcaller('items') - iterkeys = operator.methodcaller('keys') - itervalues = operator.methodcaller('values') -else: - range = xrange - reduce = reduce - from itertools import imap as map - from itertools import ifilter as filter - from itertools import ifilterfalse as filterfalse - from itertools import izip as zip - from itertools import izip_longest as zip_longest - iteritems = operator.methodcaller('iteritems') - iterkeys = operator.methodcaller('iterkeys') - itervalues = operator.methodcaller('itervalues') - -try: - from importlib import import_module -except ImportError: - def import_module(name): - __import__(name) - return sys.modules[name] diff --git a/conda/_vendor/toolz/dicttoolz.py b/conda/_vendor/toolz/dicttoolz.py deleted file mode 100644 index 3b9a23d9363..00000000000 --- a/conda/_vendor/toolz/dicttoolz.py +++ /dev/null @@ -1,315 +0,0 @@ -import copy -import operator -from conda._vendor.toolz.compatibility import (map, zip, iteritems, iterkeys, itervalues, - reduce) - -__all__ = ('merge', 'merge_with', 'valmap', 'keymap', 'itemmap', - 'valfilter', 'keyfilter', 'itemfilter', - 'assoc', 'dissoc', 'assoc_in', 'update_in', 'get_in') - - -def _get_factory(f, kwargs): - factory = kwargs.pop('factory', dict) - if kwargs: - raise TypeError("{0}() got an unexpected keyword argument " - "'{1}'".format(f.__name__, kwargs.popitem()[0])) - return factory - - -def merge(*dicts, **kwargs): - """ Merge a collection of dictionaries - - >>> merge({1: 'one'}, {2: 'two'}) - {1: 'one', 2: 'two'} - - Later dictionaries have precedence - - >>> merge({1: 2, 3: 4}, {3: 3, 4: 4}) - {1: 2, 3: 3, 4: 4} - - See Also: - merge_with - """ - if len(dicts) == 1 and not isinstance(dicts[0], dict): - dicts = dicts[0] - factory = _get_factory(merge, kwargs) - - rv = factory() - for d in dicts: - rv.update(d) - return rv - - -def merge_with(func, *dicts, **kwargs): - """ Merge dictionaries and apply function to combined values - - A key may occur in more than one dict, and all values mapped from the key - will be passed to the function as a list, such as func([val1, val2, ...]). - - >>> merge_with(sum, {1: 1, 2: 2}, {1: 10, 2: 20}) - {1: 11, 2: 22} - - >>> merge_with(first, {1: 1, 2: 2}, {2: 20, 3: 30}) # doctest: +SKIP - {1: 1, 2: 2, 3: 30} - - See Also: - merge - """ - if len(dicts) == 1 and not isinstance(dicts[0], dict): - dicts = dicts[0] - factory = _get_factory(merge_with, kwargs) - - result = factory() - for d in dicts: - for k, v in iteritems(d): - if k not in result: - result[k] = [v] - else: - result[k].append(v) - return valmap(func, result, factory) - - -def valmap(func, d, factory=dict): - """ Apply function to values of dictionary - - >>> bills = {"Alice": [20, 15, 30], "Bob": [10, 35]} - >>> valmap(sum, bills) # doctest: +SKIP - {'Alice': 65, 'Bob': 45} - - See Also: - keymap - itemmap - """ - rv = factory() - rv.update(zip(iterkeys(d), map(func, itervalues(d)))) - return rv - - -def keymap(func, d, factory=dict): - """ Apply function to keys of dictionary - - >>> bills = {"Alice": [20, 15, 30], "Bob": [10, 35]} - >>> keymap(str.lower, bills) # doctest: +SKIP - {'alice': [20, 15, 30], 'bob': [10, 35]} - - See Also: - valmap - itemmap - """ - rv = factory() - rv.update(zip(map(func, iterkeys(d)), itervalues(d))) - return rv - - -def itemmap(func, d, factory=dict): - """ Apply function to items of dictionary - - >>> accountids = {"Alice": 10, "Bob": 20} - >>> itemmap(reversed, accountids) # doctest: +SKIP - {10: "Alice", 20: "Bob"} - - See Also: - keymap - valmap - """ - rv = factory() - rv.update(map(func, iteritems(d))) - return rv - - -def valfilter(predicate, d, factory=dict): - """ Filter items in dictionary by value - - >>> iseven = lambda x: x % 2 == 0 - >>> d = {1: 2, 2: 3, 3: 4, 4: 5} - >>> valfilter(iseven, d) - {1: 2, 3: 4} - - See Also: - keyfilter - itemfilter - valmap - """ - rv = factory() - for k, v in iteritems(d): - if predicate(v): - rv[k] = v - return rv - - -def keyfilter(predicate, d, factory=dict): - """ Filter items in dictionary by key - - >>> iseven = lambda x: x % 2 == 0 - >>> d = {1: 2, 2: 3, 3: 4, 4: 5} - >>> keyfilter(iseven, d) - {2: 3, 4: 5} - - See Also: - valfilter - itemfilter - keymap - """ - rv = factory() - for k, v in iteritems(d): - if predicate(k): - rv[k] = v - return rv - - -def itemfilter(predicate, d, factory=dict): - """ Filter items in dictionary by item - - >>> def isvalid(item): - ... k, v = item - ... return k % 2 == 0 and v < 4 - - >>> d = {1: 2, 2: 3, 3: 4, 4: 5} - >>> itemfilter(isvalid, d) - {2: 3} - - See Also: - keyfilter - valfilter - itemmap - """ - rv = factory() - for item in iteritems(d): - if predicate(item): - k, v = item - rv[k] = v - return rv - - -def assoc(d, key, value, factory=dict): - """ Return a new dict with new key value pair - - New dict has d[key] set to value. Does not modify the initial dictionary. - - >>> assoc({'x': 1}, 'x', 2) - {'x': 2} - >>> assoc({'x': 1}, 'y', 3) # doctest: +SKIP - {'x': 1, 'y': 3} - """ - d2 = factory() - d2[key] = value - return merge(d, d2, factory=factory) - - -def dissoc(d, *keys): - """ Return a new dict with the given key(s) removed. - - New dict has d[key] deleted for each supplied key. - Does not modify the initial dictionary. - - >>> dissoc({'x': 1, 'y': 2}, 'y') - {'x': 1} - >>> dissoc({'x': 1, 'y': 2}, 'y', 'x') - {} - >>> dissoc({'x': 1}, 'y') # Ignores missing keys - {'x': 1} - """ - d2 = copy.copy(d) - for key in keys: - if key in d2: - del d2[key] - return d2 - - -def assoc_in(d, keys, value, factory=dict): - """ Return a new dict with new, potentially nested, key value pair - - >>> purchase = {'name': 'Alice', - ... 'order': {'items': ['Apple', 'Orange'], - ... 'costs': [0.50, 1.25]}, - ... 'credit card': '5555-1234-1234-1234'} - >>> assoc_in(purchase, ['order', 'costs'], [0.25, 1.00]) # doctest: +SKIP - {'credit card': '5555-1234-1234-1234', - 'name': 'Alice', - 'order': {'costs': [0.25, 1.00], 'items': ['Apple', 'Orange']}} - """ - return update_in(d, keys, lambda x: value, value, factory) - - -def update_in(d, keys, func, default=None, factory=dict): - """ Update value in a (potentially) nested dictionary - - inputs: - d - dictionary on which to operate - keys - list or tuple giving the location of the value to be changed in d - func - function to operate on that value - - If keys == [k0,..,kX] and d[k0]..[kX] == v, update_in returns a copy of the - original dictionary with v replaced by func(v), but does not mutate the - original dictionary. - - If k0 is not a key in d, update_in creates nested dictionaries to the depth - specified by the keys, with the innermost value set to func(default). - - >>> inc = lambda x: x + 1 - >>> update_in({'a': 0}, ['a'], inc) - {'a': 1} - - >>> transaction = {'name': 'Alice', - ... 'purchase': {'items': ['Apple', 'Orange'], - ... 'costs': [0.50, 1.25]}, - ... 'credit card': '5555-1234-1234-1234'} - >>> update_in(transaction, ['purchase', 'costs'], sum) # doctest: +SKIP - {'credit card': '5555-1234-1234-1234', - 'name': 'Alice', - 'purchase': {'costs': 1.75, 'items': ['Apple', 'Orange']}} - - >>> # updating a value when k0 is not in d - >>> update_in({}, [1, 2, 3], str, default="bar") - {1: {2: {3: 'bar'}}} - >>> update_in({1: 'foo'}, [2, 3, 4], inc, 0) - {1: 'foo', 2: {3: {4: 1}}} - """ - assert len(keys) > 0 - k, ks = keys[0], keys[1:] - if ks: - return assoc(d, k, update_in(d[k] if (k in d) else factory(), - ks, func, default, factory), - factory) - else: - innermost = func(d[k]) if (k in d) else func(default) - return assoc(d, k, innermost, factory) - - -def get_in(keys, coll, default=None, no_default=False): - """ Returns coll[i0][i1]...[iX] where [i0, i1, ..., iX]==keys. - - If coll[i0][i1]...[iX] cannot be found, returns ``default``, unless - ``no_default`` is specified, then it raises KeyError or IndexError. - - ``get_in`` is a generalization of ``operator.getitem`` for nested data - structures such as dictionaries and lists. - - >>> transaction = {'name': 'Alice', - ... 'purchase': {'items': ['Apple', 'Orange'], - ... 'costs': [0.50, 1.25]}, - ... 'credit card': '5555-1234-1234-1234'} - >>> get_in(['purchase', 'items', 0], transaction) - 'Apple' - >>> get_in(['name'], transaction) - 'Alice' - >>> get_in(['purchase', 'total'], transaction) - >>> get_in(['purchase', 'items', 'apple'], transaction) - >>> get_in(['purchase', 'items', 10], transaction) - >>> get_in(['purchase', 'total'], transaction, 0) - 0 - >>> get_in(['y'], {}, no_default=True) - Traceback (most recent call last): - ... - KeyError: 'y' - - See Also: - itertoolz.get - operator.getitem - """ - try: - return reduce(operator.getitem, keys, coll) - except (KeyError, IndexError, TypeError): - if no_default: - raise - return default diff --git a/conda/_vendor/toolz/itertoolz.py b/conda/_vendor/toolz/itertoolz.py deleted file mode 100644 index 31aece65d08..00000000000 --- a/conda/_vendor/toolz/itertoolz.py +++ /dev/null @@ -1,982 +0,0 @@ -import itertools -import heapq -import collections -import operator -from functools import partial -from random import Random -from conda._vendor.toolz.compatibility import (map, filterfalse, zip, zip_longest, iteritems, - filter) -from conda._vendor.toolz.utils import no_default - - -__all__ = ('remove', 'accumulate', 'groupby', 'merge_sorted', 'interleave', - 'unique', 'isiterable', 'isdistinct', 'take', 'drop', 'take_nth', - 'first', 'second', 'nth', 'last', 'get', 'concat', 'concatv', - 'mapcat', 'cons', 'interpose', 'frequencies', 'reduceby', 'iterate', - 'sliding_window', 'partition', 'partition_all', 'count', 'pluck', - 'join', 'tail', 'diff', 'topk', 'peek', 'random_sample') - - -def remove(predicate, seq): - """ Return those items of sequence for which predicate(item) is False - - >>> def iseven(x): - ... return x % 2 == 0 - >>> list(remove(iseven, [1, 2, 3, 4])) - [1, 3] - """ - return filterfalse(predicate, seq) - - -def accumulate(binop, seq, initial=no_default): - """ Repeatedly apply binary function to a sequence, accumulating results - - >>> from operator import add, mul - >>> list(accumulate(add, [1, 2, 3, 4, 5])) - [1, 3, 6, 10, 15] - >>> list(accumulate(mul, [1, 2, 3, 4, 5])) - [1, 2, 6, 24, 120] - - Accumulate is similar to ``reduce`` and is good for making functions like - cumulative sum: - - >>> from functools import partial, reduce - >>> sum = partial(reduce, add) - >>> cumsum = partial(accumulate, add) - - Accumulate also takes an optional argument that will be used as the first - value. This is similar to reduce. - - >>> list(accumulate(add, [1, 2, 3], -1)) - [-1, 0, 2, 5] - >>> list(accumulate(add, [], 1)) - [1] - - See Also: - itertools.accumulate : In standard itertools for Python 3.2+ - """ - seq = iter(seq) - result = next(seq) if initial == no_default else initial - yield result - for elem in seq: - result = binop(result, elem) - yield result - - -def groupby(key, seq): - """ Group a collection by a key function - - >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank'] - >>> groupby(len, names) # doctest: +SKIP - {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']} - - >>> iseven = lambda x: x % 2 == 0 - >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8]) # doctest: +SKIP - {False: [1, 3, 5, 7], True: [2, 4, 6, 8]} - - Non-callable keys imply grouping on a member. - - >>> groupby('gender', [{'name': 'Alice', 'gender': 'F'}, - ... {'name': 'Bob', 'gender': 'M'}, - ... {'name': 'Charlie', 'gender': 'M'}]) # doctest:+SKIP - {'F': [{'gender': 'F', 'name': 'Alice'}], - 'M': [{'gender': 'M', 'name': 'Bob'}, - {'gender': 'M', 'name': 'Charlie'}]} - - See Also: - countby - """ - if not callable(key): - key = getter(key) - d = collections.defaultdict(lambda: [].append) - for item in seq: - d[key(item)](item) - rv = {} - for k, v in iteritems(d): - rv[k] = v.__self__ - return rv - - -def merge_sorted(*seqs, **kwargs): - """ Merge and sort a collection of sorted collections - - This works lazily and only keeps one value from each iterable in memory. - - >>> list(merge_sorted([1, 3, 5], [2, 4, 6])) - [1, 2, 3, 4, 5, 6] - - >>> ''.join(merge_sorted('abc', 'abc', 'abc')) - 'aaabbbccc' - - The "key" function used to sort the input may be passed as a keyword. - - >>> list(merge_sorted([2, 3], [1, 3], key=lambda x: x // 3)) - [2, 1, 3, 3] - """ - if len(seqs) == 0: - return iter([]) - elif len(seqs) == 1: - return iter(seqs[0]) - - key = kwargs.get('key', None) - if key is None: - return _merge_sorted_binary(seqs) - else: - return _merge_sorted_binary_key(seqs, key) - - -def _merge_sorted_binary(seqs): - mid = len(seqs) // 2 - L1 = seqs[:mid] - if len(L1) == 1: - seq1 = iter(L1[0]) - else: - seq1 = _merge_sorted_binary(L1) - L2 = seqs[mid:] - if len(L2) == 1: - seq2 = iter(L2[0]) - else: - seq2 = _merge_sorted_binary(L2) - - try: - val2 = next(seq2) - except StopIteration: - for val1 in seq1: - yield val1 - return - - for val1 in seq1: - if val2 < val1: - yield val2 - for val2 in seq2: - if val2 < val1: - yield val2 - else: - yield val1 - break - else: - break - else: - yield val1 - else: - yield val2 - for val2 in seq2: - yield val2 - return - yield val1 - for val1 in seq1: - yield val1 - - -def _merge_sorted_binary_key(seqs, key): - mid = len(seqs) // 2 - L1 = seqs[:mid] - if len(L1) == 1: - seq1 = iter(L1[0]) - else: - seq1 = _merge_sorted_binary_key(L1, key) - L2 = seqs[mid:] - if len(L2) == 1: - seq2 = iter(L2[0]) - else: - seq2 = _merge_sorted_binary_key(L2, key) - - try: - val2 = next(seq2) - except StopIteration: - for val1 in seq1: - yield val1 - return - key2 = key(val2) - - for val1 in seq1: - key1 = key(val1) - if key2 < key1: - yield val2 - for val2 in seq2: - key2 = key(val2) - if key2 < key1: - yield val2 - else: - yield val1 - break - else: - break - else: - yield val1 - else: - yield val2 - for val2 in seq2: - yield val2 - return - yield val1 - for val1 in seq1: - yield val1 - - -def interleave(seqs): - """ Interleave a sequence of sequences - - >>> list(interleave([[1, 2], [3, 4]])) - [1, 3, 2, 4] - - >>> ''.join(interleave(('ABC', 'XY'))) - 'AXBYC' - - Both the individual sequences and the sequence of sequences may be infinite - - Returns a lazy iterator - """ - iters = itertools.cycle(map(iter, seqs)) - while True: - try: - for itr in iters: - yield next(itr) - return - except StopIteration: - predicate = partial(operator.is_not, itr) - iters = itertools.cycle(itertools.takewhile(predicate, iters)) - - -def unique(seq, key=None): - """ Return only unique elements of a sequence - - >>> tuple(unique((1, 2, 3))) - (1, 2, 3) - >>> tuple(unique((1, 2, 1, 3))) - (1, 2, 3) - - Uniqueness can be defined by key keyword - - >>> tuple(unique(['cat', 'mouse', 'dog', 'hen'], key=len)) - ('cat', 'mouse') - """ - seen = set() - seen_add = seen.add - if key is None: - for item in seq: - if item not in seen: - seen_add(item) - yield item - else: # calculate key - for item in seq: - val = key(item) - if val not in seen: - seen_add(val) - yield item - - -def isiterable(x): - """ Is x iterable? - - >>> isiterable([1, 2, 3]) - True - >>> isiterable('abc') - True - >>> isiterable(5) - False - """ - try: - iter(x) - return True - except TypeError: - return False - - -def isdistinct(seq): - """ All values in sequence are distinct - - >>> isdistinct([1, 2, 3]) - True - >>> isdistinct([1, 2, 1]) - False - - >>> isdistinct("Hello") - False - >>> isdistinct("World") - True - """ - if iter(seq) is seq: - seen = set() - seen_add = seen.add - for item in seq: - if item in seen: - return False - seen_add(item) - return True - else: - return len(seq) == len(set(seq)) - - -def take(n, seq): - """ The first n elements of a sequence - - >>> list(take(2, [10, 20, 30, 40, 50])) - [10, 20] - - See Also: - drop - tail - """ - return itertools.islice(seq, n) - - -def tail(n, seq): - """ The last n elements of a sequence - - >>> tail(2, [10, 20, 30, 40, 50]) - [40, 50] - - See Also: - drop - take - """ - try: - return seq[-n:] - except (TypeError, KeyError): - return tuple(collections.deque(seq, n)) - - -def drop(n, seq): - """ The sequence following the first n elements - - >>> list(drop(2, [10, 20, 30, 40, 50])) - [30, 40, 50] - - See Also: - take - tail - """ - return itertools.islice(seq, n, None) - - -def take_nth(n, seq): - """ Every nth item in seq - - >>> list(take_nth(2, [10, 20, 30, 40, 50])) - [10, 30, 50] - """ - return itertools.islice(seq, 0, None, n) - - -def first(seq): - """ The first element in a sequence - - >>> first('ABC') - 'A' - """ - return next(iter(seq)) - - -def second(seq): - """ The second element in a sequence - - >>> second('ABC') - 'B' - """ - return next(itertools.islice(seq, 1, None)) - - -def nth(n, seq): - """ The nth element in a sequence - - >>> nth(1, 'ABC') - 'B' - """ - if isinstance(seq, (tuple, list, collections.Sequence)): - return seq[n] - else: - return next(itertools.islice(seq, n, None)) - - -def last(seq): - """ The last element in a sequence - - >>> last('ABC') - 'C' - """ - return tail(1, seq)[0] - - -rest = partial(drop, 1) - - -def _get(ind, seq, default): - try: - return seq[ind] - except (KeyError, IndexError): - return default - - -def get(ind, seq, default=no_default): - """ Get element in a sequence or dict - - Provides standard indexing - - >>> get(1, 'ABC') # Same as 'ABC'[1] - 'B' - - Pass a list to get multiple values - - >>> get([1, 2], 'ABC') # ('ABC'[1], 'ABC'[2]) - ('B', 'C') - - Works on any value that supports indexing/getitem - For example here we see that it works with dictionaries - - >>> phonebook = {'Alice': '555-1234', - ... 'Bob': '555-5678', - ... 'Charlie':'555-9999'} - >>> get('Alice', phonebook) - '555-1234' - - >>> get(['Alice', 'Bob'], phonebook) - ('555-1234', '555-5678') - - Provide a default for missing values - - >>> get(['Alice', 'Dennis'], phonebook, None) - ('555-1234', None) - - See Also: - pluck - """ - try: - return seq[ind] - except TypeError: # `ind` may be a list - if isinstance(ind, list): - if default == no_default: - if len(ind) > 1: - return operator.itemgetter(*ind)(seq) - elif ind: - return (seq[ind[0]],) - else: - return () - else: - return tuple(_get(i, seq, default) for i in ind) - elif default != no_default: - return default - else: - raise - except (KeyError, IndexError): # we know `ind` is not a list - if default == no_default: - raise - else: - return default - - -def concat(seqs): - """ Concatenate zero or more iterables, any of which may be infinite. - - An infinite sequence will prevent the rest of the arguments from - being included. - - We use chain.from_iterable rather than ``chain(*seqs)`` so that seqs - can be a generator. - - >>> list(concat([[], [1], [2, 3]])) - [1, 2, 3] - - See also: - itertools.chain.from_iterable equivalent - """ - return itertools.chain.from_iterable(seqs) - - -def concatv(*seqs): - """ Variadic version of concat - - >>> list(concatv([], ["a"], ["b", "c"])) - ['a', 'b', 'c'] - - See also: - itertools.chain - """ - return concat(seqs) - - -def mapcat(func, seqs): - """ Apply func to each sequence in seqs, concatenating results. - - >>> list(mapcat(lambda s: [c.upper() for c in s], - ... [["a", "b"], ["c", "d", "e"]])) - ['A', 'B', 'C', 'D', 'E'] - """ - return concat(map(func, seqs)) - - -def cons(el, seq): - """ Add el to beginning of (possibly infinite) sequence seq. - - >>> list(cons(1, [2, 3])) - [1, 2, 3] - """ - return itertools.chain([el], seq) - - -def interpose(el, seq): - """ Introduce element between each pair of elements in seq - - >>> list(interpose("a", [1, 2, 3])) - [1, 'a', 2, 'a', 3] - """ - inposed = concat(zip(itertools.repeat(el), seq)) - next(inposed) - return inposed - - -def frequencies(seq): - """ Find number of occurrences of each value in seq - - >>> frequencies(['cat', 'cat', 'ox', 'pig', 'pig', 'cat']) #doctest: +SKIP - {'cat': 3, 'ox': 1, 'pig': 2} - - See Also: - countby - groupby - """ - d = collections.defaultdict(int) - for item in seq: - d[item] += 1 - return dict(d) - - -def reduceby(key, binop, seq, init=no_default): - """ Perform a simultaneous groupby and reduction - - The computation: - - >>> result = reduceby(key, binop, seq, init) # doctest: +SKIP - - is equivalent to the following: - - >>> def reduction(group): # doctest: +SKIP - ... return reduce(binop, group, init) # doctest: +SKIP - - >>> groups = groupby(key, seq) # doctest: +SKIP - >>> result = valmap(reduction, groups) # doctest: +SKIP - - But the former does not build the intermediate groups, allowing it to - operate in much less space. This makes it suitable for larger datasets - that do not fit comfortably in memory - - The ``init`` keyword argument is the default initialization of the - reduction. This can be either a constant value like ``0`` or a callable - like ``lambda : 0`` as might be used in ``defaultdict``. - - Simple Examples - --------------- - - >>> from operator import add, mul - >>> iseven = lambda x: x % 2 == 0 - - >>> data = [1, 2, 3, 4, 5] - - >>> reduceby(iseven, add, data) # doctest: +SKIP - {False: 9, True: 6} - - >>> reduceby(iseven, mul, data) # doctest: +SKIP - {False: 15, True: 8} - - Complex Example - --------------- - - >>> projects = [{'name': 'build roads', 'state': 'CA', 'cost': 1000000}, - ... {'name': 'fight crime', 'state': 'IL', 'cost': 100000}, - ... {'name': 'help farmers', 'state': 'IL', 'cost': 2000000}, - ... {'name': 'help farmers', 'state': 'CA', 'cost': 200000}] - - >>> reduceby('state', # doctest: +SKIP - ... lambda acc, x: acc + x['cost'], - ... projects, 0) - {'CA': 1200000, 'IL': 2100000} - - Example Using ``init`` - ---------------------- - - >>> def set_add(s, i): - ... s.add(i) - ... return s - - >>> reduceby(iseven, set_add, [1, 2, 3, 4, 1, 2, 3], set) # doctest: +SKIP - {True: set([2, 4]), - False: set([1, 3])} - """ - is_no_default = init == no_default - if not is_no_default and not callable(init): - _init = init - init = lambda: _init - if not callable(key): - key = getter(key) - d = {} - for item in seq: - k = key(item) - if k not in d: - if is_no_default: - d[k] = item - continue - else: - d[k] = init() - d[k] = binop(d[k], item) - return d - - -def iterate(func, x): - """ Repeatedly apply a function func onto an original input - - Yields x, then func(x), then func(func(x)), then func(func(func(x))), etc.. - - >>> def inc(x): return x + 1 - >>> counter = iterate(inc, 0) - >>> next(counter) - 0 - >>> next(counter) - 1 - >>> next(counter) - 2 - - >>> double = lambda x: x * 2 - >>> powers_of_two = iterate(double, 1) - >>> next(powers_of_two) - 1 - >>> next(powers_of_two) - 2 - >>> next(powers_of_two) - 4 - >>> next(powers_of_two) - 8 - """ - while True: - yield x - x = func(x) - - -def sliding_window(n, seq): - """ A sequence of overlapping subsequences - - >>> list(sliding_window(2, [1, 2, 3, 4])) - [(1, 2), (2, 3), (3, 4)] - - This function creates a sliding window suitable for transformations like - sliding means / smoothing - - >>> mean = lambda seq: float(sum(seq)) / len(seq) - >>> list(map(mean, sliding_window(2, [1, 2, 3, 4]))) - [1.5, 2.5, 3.5] - """ - return zip(*(collections.deque(itertools.islice(it, i), 0) or it - for i, it in enumerate(itertools.tee(seq, n)))) - - -no_pad = '__no__pad__' - - -def partition(n, seq, pad=no_pad): - """ Partition sequence into tuples of length n - - >>> list(partition(2, [1, 2, 3, 4])) - [(1, 2), (3, 4)] - - If the length of ``seq`` is not evenly divisible by ``n``, the final tuple - is dropped if ``pad`` is not specified, or filled to length ``n`` by pad: - - >>> list(partition(2, [1, 2, 3, 4, 5])) - [(1, 2), (3, 4)] - - >>> list(partition(2, [1, 2, 3, 4, 5], pad=None)) - [(1, 2), (3, 4), (5, None)] - - See Also: - partition_all - """ - args = [iter(seq)] * n - if pad is no_pad: - return zip(*args) - else: - return zip_longest(*args, fillvalue=pad) - - -def partition_all(n, seq): - """ Partition all elements of sequence into tuples of length at most n - - The final tuple may be shorter to accommodate extra elements. - - >>> list(partition_all(2, [1, 2, 3, 4])) - [(1, 2), (3, 4)] - - >>> list(partition_all(2, [1, 2, 3, 4, 5])) - [(1, 2), (3, 4), (5,)] - - See Also: - partition - """ - args = [iter(seq)] * n - it = zip_longest(*args, fillvalue=no_pad) - try: - prev = next(it) - except StopIteration: - return - for item in it: - yield prev - prev = item - if prev[-1] is no_pad: - yield prev[:prev.index(no_pad)] - else: - yield prev - - -def count(seq): - """ Count the number of items in seq - - Like the builtin ``len`` but works on lazy sequencies. - - Not to be confused with ``itertools.count`` - - See also: - len - """ - if hasattr(seq, '__len__'): - return len(seq) - return sum(1 for i in seq) - - -def pluck(ind, seqs, default=no_default): - """ plucks an element or several elements from each item in a sequence. - - ``pluck`` maps ``itertoolz.get`` over a sequence and returns one or more - elements of each item in the sequence. - - This is equivalent to running `map(curried.get(ind), seqs)` - - ``ind`` can be either a single string/index or a list of strings/indices. - ``seqs`` should be sequence containing sequences or dicts. - - e.g. - - >>> data = [{'id': 1, 'name': 'Cheese'}, {'id': 2, 'name': 'Pies'}] - >>> list(pluck('name', data)) - ['Cheese', 'Pies'] - >>> list(pluck([0, 1], [[1, 2, 3], [4, 5, 7]])) - [(1, 2), (4, 5)] - - See Also: - get - map - """ - if default == no_default: - get = getter(ind) - return map(get, seqs) - elif isinstance(ind, list): - return (tuple(_get(item, seq, default) for item in ind) - for seq in seqs) - return (_get(ind, seq, default) for seq in seqs) - - -def getter(index): - if isinstance(index, list): - if len(index) == 1: - index = index[0] - return lambda x: (x[index],) - elif index: - return operator.itemgetter(*index) - else: - return lambda x: () - else: - return operator.itemgetter(index) - - -def join(leftkey, leftseq, rightkey, rightseq, - left_default=no_default, right_default=no_default): - """ Join two sequences on common attributes - - This is a semi-streaming operation. The LEFT sequence is fully evaluated - and placed into memory. The RIGHT sequence is evaluated lazily and so can - be arbitrarily large. - - >>> friends = [('Alice', 'Edith'), - ... ('Alice', 'Zhao'), - ... ('Edith', 'Alice'), - ... ('Zhao', 'Alice'), - ... ('Zhao', 'Edith')] - - >>> cities = [('Alice', 'NYC'), - ... ('Alice', 'Chicago'), - ... ('Dan', 'Syndey'), - ... ('Edith', 'Paris'), - ... ('Edith', 'Berlin'), - ... ('Zhao', 'Shanghai')] - - >>> # Vacation opportunities - >>> # In what cities do people have friends? - >>> result = join(second, friends, - ... first, cities) - >>> for ((a, b), (c, d)) in sorted(unique(result)): - ... print((a, d)) - ('Alice', 'Berlin') - ('Alice', 'Paris') - ('Alice', 'Shanghai') - ('Edith', 'Chicago') - ('Edith', 'NYC') - ('Zhao', 'Chicago') - ('Zhao', 'NYC') - ('Zhao', 'Berlin') - ('Zhao', 'Paris') - - Specify outer joins with keyword arguments ``left_default`` and/or - ``right_default``. Here is a full outer join in which unmatched elements - are paired with None. - - >>> identity = lambda x: x - >>> list(join(identity, [1, 2, 3], - ... identity, [2, 3, 4], - ... left_default=None, right_default=None)) - [(2, 2), (3, 3), (None, 4), (1, None)] - - Usually the key arguments are callables to be applied to the sequences. If - the keys are not obviously callable then it is assumed that indexing was - intended, e.g. the following is a legal change - - >>> # result = join(second, friends, first, cities) - >>> result = join(1, friends, 0, cities) # doctest: +SKIP - """ - if not callable(leftkey): - leftkey = getter(leftkey) - if not callable(rightkey): - rightkey = getter(rightkey) - - d = groupby(leftkey, leftseq) - seen_keys = set() - - left_default_is_no_default = (left_default == no_default) - for item in rightseq: - key = rightkey(item) - seen_keys.add(key) - try: - left_matches = d[key] - for match in left_matches: - yield (match, item) - except KeyError: - if not left_default_is_no_default: - yield (left_default, item) - - if right_default != no_default: - for key, matches in d.items(): - if key not in seen_keys: - for match in matches: - yield (match, right_default) - - -def diff(*seqs, **kwargs): - """ Return those items that differ between sequences - - >>> list(diff([1, 2, 3], [1, 2, 10, 100])) - [(3, 10)] - - Shorter sequences may be padded with a ``default`` value: - - >>> list(diff([1, 2, 3], [1, 2, 10, 100], default=None)) - [(3, 10), (None, 100)] - - A ``key`` function may also be applied to each item to use during - comparisons: - - >>> list(diff(['apples', 'bananas'], ['Apples', 'Oranges'], key=str.lower)) - [('bananas', 'Oranges')] - """ - N = len(seqs) - if N == 1 and isinstance(seqs[0], list): - seqs = seqs[0] - N = len(seqs) - if N < 2: - raise TypeError('Too few sequences given (min 2 required)') - default = kwargs.get('default', no_default) - if default == no_default: - iters = zip(*seqs) - else: - iters = zip_longest(*seqs, fillvalue=default) - key = kwargs.get('key', None) - if key is None: - for items in iters: - if items.count(items[0]) != N: - yield items - else: - for items in iters: - vals = tuple(map(key, items)) - if vals.count(vals[0]) != N: - yield items - - -def topk(k, seq, key=None): - """ Find the k largest elements of a sequence - - Operates lazily in ``n*log(k)`` time - - >>> topk(2, [1, 100, 10, 1000]) - (1000, 100) - - Use a key function to change sorted order - - >>> topk(2, ['Alice', 'Bob', 'Charlie', 'Dan'], key=len) - ('Charlie', 'Alice') - - See also: - heapq.nlargest - """ - if key is not None and not callable(key): - key = getter(key) - return tuple(heapq.nlargest(k, seq, key=key)) - - -def peek(seq): - """ Retrieve the next element of a sequence - - Returns the first element and an iterable equivalent to the original - sequence, still having the element retrieved. - - >>> seq = [0, 1, 2, 3, 4] - >>> first, seq = peek(seq) - >>> first - 0 - >>> list(seq) - [0, 1, 2, 3, 4] - """ - iterator = iter(seq) - item = next(iterator) - return item, itertools.chain([item], iterator) - - -def random_sample(prob, seq, random_state=None): - """ Return elements from a sequence with probability of prob - - Returns a lazy iterator of random items from seq. - - ``random_sample`` considers each item independently and without - replacement. See below how the first time it returned 13 items and the - next time it returned 6 items. - - >>> seq = list(range(100)) - >>> list(random_sample(0.1, seq)) # doctest: +SKIP - [6, 9, 19, 35, 45, 50, 58, 62, 68, 72, 78, 86, 95] - >>> list(random_sample(0.1, seq)) # doctest: +SKIP - [6, 44, 54, 61, 69, 94] - - Providing an integer seed for ``random_state`` will result in - deterministic sampling. Given the same seed it will return the same sample - every time. - - >>> list(random_sample(0.1, seq, random_state=2016)) - [7, 9, 19, 25, 30, 32, 34, 48, 59, 60, 81, 98] - >>> list(random_sample(0.1, seq, random_state=2016)) - [7, 9, 19, 25, 30, 32, 34, 48, 59, 60, 81, 98] - - ``random_state`` can also be any object with a method ``random`` that - returns floats between 0.0 and 1.0 (exclusive). - - >>> from random import Random - >>> randobj = Random(2016) - >>> list(random_sample(0.1, seq, random_state=randobj)) - [7, 9, 19, 25, 30, 32, 34, 48, 59, 60, 81, 98] - """ - if not hasattr(random_state, 'random'): - random_state = Random(random_state) - return filter(lambda _: random_state.random() < prob, seq) diff --git a/conda/_vendor/toolz/recipes.py b/conda/_vendor/toolz/recipes.py deleted file mode 100644 index 08c6c8c1e2a..00000000000 --- a/conda/_vendor/toolz/recipes.py +++ /dev/null @@ -1,47 +0,0 @@ -import itertools -from .itertoolz import frequencies, pluck, getter -from .compatibility import map - - -__all__ = ('countby', 'partitionby') - - -def countby(key, seq): - """ Count elements of a collection by a key function - - >>> countby(len, ['cat', 'mouse', 'dog']) - {3: 2, 5: 1} - - >>> def iseven(x): return x % 2 == 0 - >>> countby(iseven, [1, 2, 3]) # doctest:+SKIP - {True: 1, False: 2} - - See Also: - groupby - """ - if not callable(key): - key = getter(key) - return frequencies(map(key, seq)) - - -def partitionby(func, seq): - """ Partition a sequence according to a function - - Partition `s` into a sequence of lists such that, when traversing - `s`, every time the output of `func` changes a new list is started - and that and subsequent items are collected into that list. - - >>> is_space = lambda c: c == " " - >>> list(partitionby(is_space, "I have space")) - [('I',), (' ',), ('h', 'a', 'v', 'e'), (' ',), ('s', 'p', 'a', 'c', 'e')] - - >>> is_large = lambda x: x > 10 - >>> list(partitionby(is_large, [1, 2, 1, 99, 88, 33, 99, -1, 5])) - [(1, 2, 1), (99, 88, 33, 99), (-1, 5)] - - See also: - partition - groupby - itertools.groupby - """ - return map(tuple, pluck(1, itertools.groupby(seq, key=func))) diff --git a/conda/_vendor/toolz/utils.py b/conda/_vendor/toolz/utils.py deleted file mode 100644 index 1002c4649f8..00000000000 --- a/conda/_vendor/toolz/utils.py +++ /dev/null @@ -1,9 +0,0 @@ -def raises(err, lamda): - try: - lamda() - return False - except err: - return True - - -no_default = '__no__default__' diff --git a/conda/_vendor/vendor.txt b/conda/_vendor/vendor.txt index b0b31647242..3d36f21c7fa 100644 --- a/conda/_vendor/vendor.txt +++ b/conda/_vendor/vendor.txt @@ -1,5 +1,4 @@ boltons==21.0.0 -toolz==0.9.0 tqdm==4.61.1 urllib3==1.19.1 appdirs==1.2.0 diff --git a/conda/activate.py b/conda/activate.py index 279608804e5..4a15fa51953 100644 --- a/conda/activate.py +++ b/conda/activate.py @@ -11,10 +11,11 @@ import sys from textwrap import dedent +from tlz.itertoolz import concatv, drop + # Since we have to have configuration context here, anything imported by # conda.base.context is fair game, but nothing more. from . import CONDA_PACKAGE_ROOT, CONDA_SOURCE_ROOT -from ._vendor.toolz import concatv, drop from .auxlib.compat import Utf8NamedTemporaryFile from .base.constants import PREFIX_STATE_FILE, PACKAGE_ENV_VARS_DIR, CONDA_ENV_VARS_UNSET_VAR from .base.context import ROOT_ENV_NAME, context, locate_prefix_by_name diff --git a/conda/base/context.py b/conda/base/context.py index 74758d81824..81f6583d22f 100644 --- a/conda/base/context.py +++ b/conda/base/context.py @@ -17,6 +17,8 @@ from datetime import datetime import warnings +from tlz.itertoolz import concat, concatv, unique + from .constants import ( APP_NAME, ChannelPriority, @@ -46,7 +48,6 @@ from ..auxlib.ish import dals from .._vendor.boltons.setutils import IndexedSet from .._vendor.frozendict import frozendict -from .._vendor.toolz import concat, concatv, unique from ..common.compat import NoneType, odict, on_win from ..common.configuration import (Configuration, ConfigurationLoadError, MapParameter, ParameterLoader, PrimitiveParameter, SequenceParameter, diff --git a/conda/cli/main_config.py b/conda/cli/main_config.py index 5b41459b00c..fd1d8371d19 100644 --- a/conda/cli/main_config.py +++ b/conda/cli/main_config.py @@ -11,9 +11,10 @@ import sys from textwrap import wrap +from tlz.itertoolz import concat, groupby + from .. import CondaError from ..auxlib.entity import EntityEncoder -from .._vendor.toolz import concat, groupby from ..base.constants import (ChannelPriority, DepsModifier, PathConflict, SafetyChecks, UpdateModifier, SatSolverChoice, ExperimentalSolverChoice) from ..base.context import context, sys_rc_path, user_rc_path diff --git a/conda/common/configuration.py b/conda/common/configuration.py index db23e638a26..83687ddcae8 100644 --- a/conda/common/configuration.py +++ b/conda/common/configuration.py @@ -27,6 +27,10 @@ from stat import S_IFDIR, S_IFMT, S_IFREG import sys +from tlz.itertoolz import concat, concatv, unique +from tlz.dicttoolz import merge, merge_with +from tlz.functoolz import excepts + from .compat import isiterable, odict, primitive_types from .constants import NULL from .path import expand @@ -37,7 +41,6 @@ from ..auxlib.type_coercion import TypeCoercionError, typify, typify_data_structure from .._vendor.frozendict import frozendict from .._vendor.boltons.setutils import IndexedSet -from .._vendor.toolz import concat, concatv, excepts, merge, merge_with, unique try: # pragma: no cover from ruamel_yaml.comments import CommentedSeq, CommentedMap diff --git a/conda/common/path.py b/conda/common/path.py index 510f15f06b4..6d9c6e3ddec 100644 --- a/conda/common/path.py +++ b/conda/common/path.py @@ -11,9 +11,10 @@ import subprocess from urllib.parse import urlsplit +from tlz.itertoolz import accumulate, concat + from .compat import on_win from .. import CondaError -from .._vendor.toolz import accumulate, concat from distutils.spawn import find_executable diff --git a/conda/common/pkg_formats/python.py b/conda/common/pkg_formats/python.py index a868b1ae762..e7a959fde4c 100644 --- a/conda/common/pkg_formats/python.py +++ b/conda/common/pkg_formats/python.py @@ -18,6 +18,8 @@ import sys import warnings +from tlz.itertoolz import concat, concatv, groupby + from ... import CondaError from ..compat import odict, open from ..path import ( @@ -25,7 +27,6 @@ ) from ...auxlib.decorators import memoizedproperty from ..._vendor.frozendict import frozendict -from ..._vendor.toolz import concat, concatv, groupby log = getLogger(__name__) diff --git a/conda/core/index.py b/conda/core/index.py index cfb97846b52..5202c246bdd 100644 --- a/conda/core/index.py +++ b/conda/core/index.py @@ -11,11 +11,12 @@ import sys import warnings +from tlz.itertoolz import concat, concatv + from .package_cache_data import PackageCacheData from .prefix_data import PrefixData from .subdir_data import SubdirData, make_feature_record from .._vendor.boltons.setutils import IndexedSet -from .._vendor.toolz import concat, concatv from ..base.context import context from ..common.io import ThreadLimitedThreadPoolExecutor, time_recorder from ..exceptions import ChannelNotAllowed, InvalidSpec diff --git a/conda/core/link.py b/conda/core/link.py index 042a7fd2ba4..c131e8b23bd 100644 --- a/conda/core/link.py +++ b/conda/core/link.py @@ -14,6 +14,8 @@ from textwrap import indent import warnings +from tlz.itertoolz import concat, concatv, interleave + from .package_cache_data import PackageCacheData from .path_actions import (CompileMultiPycAction, CreateNonadminAction, CreatePrefixRecordAction, CreatePythonEntryPointAction, LinkPathAction, MakeMenuAction, @@ -24,7 +26,6 @@ from .. import CondaError, CondaMultiError, conda_signal_handler from ..auxlib.collection import first from ..auxlib.ish import dals -from .._vendor.toolz import concat, concatv, interleave from ..base.constants import DEFAULTS_CHANNEL_NAME, PREFIX_MAGIC_FILE, SafetyChecks from ..base.context import context from ..cli.common import confirm_yn diff --git a/conda/core/package_cache_data.py b/conda/core/package_cache_data.py index 208320cd5b5..9d5028c7c35 100644 --- a/conda/core/package_cache_data.py +++ b/conda/core/package_cache_data.py @@ -13,11 +13,12 @@ from sys import platform from tarfile import ReadError +from tlz.itertoolz import concat, concatv, groupby + from .path_actions import CacheUrlAction, ExtractPackageAction from .. import CondaError, CondaMultiError, conda_signal_handler from ..auxlib.collection import first from ..auxlib.decorators import memoizemethod -from .._vendor.toolz import concat, concatv, groupby from ..base.constants import (CONDA_PACKAGE_EXTENSIONS, CONDA_PACKAGE_EXTENSION_V1, CONDA_PACKAGE_EXTENSION_V2, PACKAGE_CACHE_MAGIC_FILE) from ..base.context import context diff --git a/conda/core/path_actions.py b/conda/core/path_actions.py index 8e947ef4dc1..511542c7a70 100644 --- a/conda/core/path_actions.py +++ b/conda/core/path_actions.py @@ -11,12 +11,13 @@ import sys from uuid import uuid4 +from tlz.itertoolz import concat + from .envs_manager import get_user_environments_txt_file, register_env, unregister_env from .portability import _PaddingError, update_prefix from .prefix_data import PrefixData from .. import CondaError from ..auxlib.ish import dals -from .._vendor.toolz import concat from ..base.constants import CONDA_TEMP_EXTENSION from ..base.context import context from ..common.compat import on_win diff --git a/conda/core/solve.py b/conda/core/solve.py index 39dc47ae340..6c8072417b4 100644 --- a/conda/core/solve.py +++ b/conda/core/solve.py @@ -10,6 +10,8 @@ import sys from textwrap import dedent +from tlz.itertoolz import concat, concatv, groupby + from .index import get_reduced_index, _supplement_index_with_system from .link import PrefixSetup, UnlinkLinkTransaction from .prefix_data import PrefixData @@ -18,7 +20,6 @@ from ..auxlib.decorators import memoizedproperty from ..auxlib.ish import dals from .._vendor.boltons.setutils import IndexedSet -from .._vendor.toolz import concat, concatv, groupby from ..base.constants import (DepsModifier, UNKNOWN_CHANNEL, UpdateModifier, REPODATA_FN, ExperimentalSolverChoice) from ..base.context import context diff --git a/conda/core/subdir_data.py b/conda/core/subdir_data.py index 7ab4a1d4f6a..881ca7245ae 100644 --- a/conda/core/subdir_data.py +++ b/conda/core/subdir_data.py @@ -21,11 +21,12 @@ from time import time import warnings +from tlz.itertoolz import concat, take, groupby + from .. import CondaError from ..auxlib.ish import dals from ..auxlib.logz import stringify from .._vendor.boltons.setutils import IndexedSet -from .._vendor.toolz import concat, take, groupby from ..base.constants import CONDA_HOMEPAGE_URL, CONDA_PACKAGE_EXTENSION_V1, REPODATA_FN from ..base.constants import INITIAL_TRUST_ROOT # Where root.json is currently. from ..base.context import context diff --git a/conda/exceptions.py b/conda/exceptions.py index 389ffaed3b3..00b4bbedd94 100644 --- a/conda/exceptions.py +++ b/conda/exceptions.py @@ -16,6 +16,8 @@ from traceback import format_exception, format_exception_only import getpass +from tlz.itertoolz import groupby + from .models.channel import Channel from .common.url import join_url, maybe_unquote from . import CondaError, CondaExitZero, CondaMultiError @@ -23,7 +25,6 @@ from .auxlib.ish import dals from .auxlib.logz import stringify from .auxlib.type_coercion import boolify -from ._vendor.toolz import groupby from .base.constants import COMPATIBLE_SHELLS, PathConflict, SafetyChecks from .common.compat import ensure_text_type, on_win from .common.io import dashlist, timeout diff --git a/conda/history.py b/conda/history.py index fa518dcfe5d..d773909c4ae 100644 --- a/conda/history.py +++ b/conda/history.py @@ -16,9 +16,10 @@ import time import warnings +from tlz.itertoolz import groupby, take + from . import __version__ as CONDA_VERSION from .auxlib.ish import dals -from ._vendor.toolz import groupby, take from .base.constants import DEFAULTS_CHANNEL_NAME from .base.context import context from .common.compat import ensure_text_type, open diff --git a/conda/models/channel.py b/conda/models/channel.py index a9ec4417de9..12311197780 100644 --- a/conda/models/channel.py +++ b/conda/models/channel.py @@ -7,8 +7,9 @@ from itertools import chain from logging import getLogger +from tlz.itertoolz import concat, concatv, drop + from .._vendor.boltons.setutils import IndexedSet -from .._vendor.toolz import concat, concatv, drop from ..base.constants import DEFAULTS_CHANNEL_NAME, MAX_CHANNEL_PRIORITY, UNKNOWN_CHANNEL from ..base.context import context, Context from ..common.compat import ensure_text_type, isiterable, odict diff --git a/conda/models/match_spec.py b/conda/models/match_spec.py index e624464733d..d3ea13853be 100644 --- a/conda/models/match_spec.py +++ b/conda/models/match_spec.py @@ -12,11 +12,12 @@ from os.path import basename import re +from tlz.itertoolz import concat, concatv, groupby + from .channel import Channel from .version import BuildNumberMatch, VersionSpec from ..auxlib.collection import frozendict from ..auxlib.decorators import memoizedproperty -from .._vendor.toolz import concat, concatv, groupby from ..base.constants import CONDA_PACKAGE_EXTENSION_V1, CONDA_PACKAGE_EXTENSION_V2 from ..common.compat import isiterable from ..common.io import dashlist diff --git a/conda/models/version.py b/conda/models/version.py index 2038bb51202..92119a4efa2 100644 --- a/conda/models/version.py +++ b/conda/models/version.py @@ -7,7 +7,8 @@ import re from itertools import zip_longest -from .._vendor.toolz import excepts +from tlz.functoolz import excepts + from ..exceptions import InvalidVersionSpec log = getLogger(__name__) diff --git a/conda/plan.py b/conda/plan.py index 091ab899655..dc921def0eb 100644 --- a/conda/plan.py +++ b/conda/plan.py @@ -16,8 +16,9 @@ from logging import getLogger import sys +from tlz.itertoolz import concatv + from ._vendor.boltons.setutils import IndexedSet -from ._vendor.toolz import concatv from .base.constants import DEFAULTS_CHANNEL_NAME, UNKNOWN_CHANNEL from .base.context import context, stack_context_default from .common.io import dashlist, env_vars, time_recorder @@ -369,8 +370,8 @@ def _plan_from_actions(actions, index): # pragma: no cover def _inject_UNLINKLINKTRANSACTION(plan, index, prefix, axn, specs): # pragma: no cover from os.path import isdir + from tlz.itertoolz import groupby from .models.dist import Dist - from ._vendor.toolz.itertoolz import groupby from .instructions import LINK, PROGRESSIVEFETCHEXTRACT, UNLINK, UNLINKLINKTRANSACTION from .core.package_cache_data import ProgressiveFetchExtract from .core.link import PrefixSetup, UnlinkLinkTransaction diff --git a/conda/resolve.py b/conda/resolve.py index 0b1e92631d6..2b33843422a 100644 --- a/conda/resolve.py +++ b/conda/resolve.py @@ -9,8 +9,9 @@ from logging import DEBUG, getLogger from .auxlib.decorators import memoizemethod +from tlz.itertoolz import concat, groupby + from ._vendor.frozendict import FrozenOrderedDict as frozendict -from ._vendor.toolz import concat, groupby from ._vendor.tqdm import tqdm from .base.constants import ChannelPriority, MAX_CHANNEL_PRIORITY, SatSolverChoice from .base.context import context diff --git a/conda_env/env.py b/conda_env/env.py index fc738d945bc..0816d247ec7 100644 --- a/conda_env/env.py +++ b/conda_env/env.py @@ -23,7 +23,7 @@ from conda.history import History try: - from cytoolz.itertoolz import concatv, groupby + from tlz.itertoolz import concatv, groupby except ImportError: # pragma: no cover from conda._vendor.toolz.itertoolz import concatv, groupby # NOQA diff --git a/news/11333-replace-toolz-dependency-with-cytoolz b/news/11333-replace-toolz-dependency-with-cytoolz new file mode 100644 index 00000000000..a096bb0c8dc --- /dev/null +++ b/news/11333-replace-toolz-dependency-with-cytoolz @@ -0,0 +1,19 @@ +### Enhancements + +* Replace vendored toolz with cytoolz dependency. (#11589) + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/base/test_context.py b/tests/base/test_context.py index 5d19c8dfb90..a54a8b0a290 100644 --- a/tests/base/test_context.py +++ b/tests/base/test_context.py @@ -12,10 +12,10 @@ from unittest import TestCase, mock import pytest +from tlz.itertoolz import concat from conda.auxlib.collection import AttrDict from conda.auxlib.ish import dals -from conda._vendor.toolz.itertoolz import concat from conda.base.constants import PathConflict, ChannelPriority from conda.base.context import ( context, diff --git a/tests/core/test_path_actions.py b/tests/core/test_path_actions.py index 5c6b28350c0..3b58af94dc2 100644 --- a/tests/core/test_path_actions.py +++ b/tests/core/test_path_actions.py @@ -14,9 +14,9 @@ from uuid import uuid4 import pytest +from tlz.itertoolz import groupby from conda.auxlib.collection import AttrDict -from conda._vendor.toolz.itertoolz import groupby from conda.base.context import context from conda.common.compat import on_win from conda.common.path import get_bin_directory_short_path, get_python_noarch_target_path, \ diff --git a/tests/test_activate.py b/tests/test_activate.py index c36a9e3fd3e..babf76921b3 100644 --- a/tests/test_activate.py +++ b/tests/test_activate.py @@ -18,11 +18,11 @@ from uuid import uuid4 import pytest +from tlz.itertoolz import concatv from conda import __version__ as conda_version from conda import CONDA_PACKAGE_ROOT, CONDA_SOURCE_ROOT from conda.auxlib.ish import dals -from conda._vendor.toolz.itertoolz import concatv from conda.activate import ( CmdExeActivator, CshActivator, diff --git a/tests/test_create.py b/tests/test_create.py index 952d38d9ec1..58e8b004acf 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -8,7 +8,6 @@ from glob import glob from conda.auxlib.compat import Utf8NamedTemporaryFile -from conda._vendor.toolz.itertoolz import groupby from conda.gateways.disk.permissions import make_read_only from conda.gateways.disk.create import compile_multiple_pyc from conda.models.channel import Channel @@ -31,6 +30,7 @@ import pytest import requests +from tlz.itertoolz import groupby from conda import ( CondaError, diff --git a/tools/vendoring/patches/toolz.patch b/tools/vendoring/patches/toolz.patch deleted file mode 100644 index 190fb1ecc9e..00000000000 --- a/tools/vendoring/patches/toolz.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff --git a/conda/_vendor/toolz/__init__.py b/conda/_vendor/toolz/__init__.py -index 1e1cbe8..3a7d1e3 100644 ---- a/conda/_vendor/toolz/__init__.py -+++ b/conda/_vendor/toolz/__init__.py -@@ -1,22 +1,26 @@ --from .itertoolz import * -- --from .functoolz import * -- --from .dicttoolz import * -- --from .recipes import * -- --from .compatibility import map, filter -- --from . import sandbox -- --from functools import partial, reduce -- --sorted = sorted -- --# Aliases --comp = compose -- --functoolz._sigs.create_signature_registry() -+try: -+ from cytoolz import __version__ as cytoolz_version -+ if tuple(int(x) for x in cytoolz_version.split(".")) < (0, 8, 2): -+ raise ImportError() -+ from cytoolz.itertoolz import * -+ from cytoolz.dicttoolz import * -+ from cytoolz.functoolz import excepts -+except (ImportError, ValueError): -+ from .itertoolz import * -+ from .dicttoolz import * -+ -+ # Importing from toolz.functoolz is slow since it imports inspect. -+ # Copy the relevant part of excepts' implementation instead: -+ class excepts(object): -+ def __init__(self, exc, func, handler=lambda exc: None): -+ self.exc = exc -+ self.func = func -+ self.handler = handler -+ -+ def __call__(self, *args, **kwargs): -+ try: -+ return self.func(*args, **kwargs) -+ except self.exc as e: -+ return self.handler(e) - - __version__ = '0.9.0'