Skip to content

Commit 10fe8e4

Browse files
Removes the usage of conda._vendor.toolz from constructor (conda#525)
* Removes the usage of toolz from conda This commit attempts to replace the usage of toolz in the main conda project. In an upcoming conda release, this will be completely removed. Co-authored-by: Ken Odegard <[email protected]>
1 parent 5799a06 commit 10fe8e4

File tree

3 files changed

+83
-23
lines changed

3 files changed

+83
-23
lines changed

constructor/conda_interface.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@
2828
# Flatten VersionOrder.version, skip epoch, and keep only major and minor
2929
CONDA_MAJOR_MINOR = tuple(chain.from_iterable(_conda_version))[1:3]
3030

31-
from conda._vendor.toolz.itertoolz import (
32-
concatv as _concatv, get as _get, groupby as _groupby,
33-
)
3431
from conda.api import SubdirData # noqa
3532
from conda.base.context import (
3633
context as _conda_context, replace_context_default as _conda_replace_context_default,
@@ -56,7 +53,7 @@
5653
# used by fcp.py
5754
PackageCacheData = _PackageCacheData
5855
Solver, read_paths_json = _Solver, _read_paths_json
59-
concatv, get, groupby, all_channel_urls = _concatv, _get, _groupby, _all_channel_urls
56+
all_channel_urls = _all_channel_urls
6057
conda_context, env_vars = _conda_context, _env_vars
6158
conda_replace_context_default = _conda_replace_context_default
6259
download, PackageCacheRecord = _download, _PackageCacheRecord

constructor/fcp.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
import json
1313
import os
1414
from os.path import isdir, isfile, join, splitext
15+
from itertools import groupby
16+
1517
import sys
1618
import tempfile
1719

1820
from constructor.utils import hash_files, filename_dist
1921
from .conda_interface import (PackageCacheData, PackageCacheRecord, Solver, SubdirData,
20-
VersionOrder, concatv, conda_context, conda_replace_context_default,
21-
download, env_vars, groupby, read_paths_json, all_channel_urls,
22+
VersionOrder, conda_context, conda_replace_context_default,
23+
download, env_vars, read_paths_json, all_channel_urls,
2224
cc_platform)
2325

2426

@@ -44,11 +46,12 @@ def warn_menu_packages_missing(precs, menu_packages):
4446

4547

4648
def check_duplicates(precs):
47-
groups = groupby(lambda x: x.name, precs)
48-
for precs in groups.values():
49-
if len(precs) > 1:
50-
sys.exit("Error: '%s' listed multiple times: %s" %
51-
(precs[0].name, ', '.join(prec.fn for prec in precs)))
49+
prec_groups = {key: tuple(value) for key, value in groupby(precs, lambda prec: prec.name)}
50+
51+
for name, precs in prec_groups.items():
52+
filenames = sorted(prec.fn for prec in precs)
53+
if len(filenames) > 1:
54+
sys.exit(f"Error: {name} listed multiple times: {' , '.join(filenames)}")
5255

5356

5457
def exclude_packages(precs, exclude=()):
@@ -57,13 +60,11 @@ def exclude_packages(precs, exclude=()):
5760
if bad_char in name:
5861
sys.exit("Error: did not expect '%s' in package name: %s" % (bad_char, name))
5962

60-
groups = groupby(lambda x: x.name in exclude, precs)
61-
excluded_precs = groups.get(True, [])
62-
accepted_precs = groups.get(False, [])
63-
for name in exclude:
64-
if not any(prec.name == name for prec in excluded_precs):
65-
sys.exit("Error: no package named '%s' to remove" % name)
66-
return accepted_precs
63+
unknown_precs = set(exclude).difference(prec.name for prec in precs)
64+
if unknown_precs:
65+
sys.exit(f"Error: no package(s) named {', '.join(unknown_precs)} to remove")
66+
67+
return [prec for prec in precs if prec.name not in exclude]
6768

6869

6970
def _find_out_of_date_precs(precs, channel_urls, platform):
@@ -245,15 +246,12 @@ def _main(name, version, download_dir, platform, channel_urls=(), channels_remap
245246
transmute_file_type=''):
246247
# Add python to specs, since all installers need a python interpreter. In the future we'll
247248
# probably want to add conda too.
248-
specs = list(concatv(specs, ("python",)))
249+
specs = (*specs, "python")
249250
if verbose:
250251
print("specs: %r" % specs)
251252

252253
# Append channels_remap srcs to channel_urls
253-
channel_urls = tuple(concatv(
254-
channel_urls,
255-
(x['src'] for x in channels_remap),
256-
))
254+
channel_urls = (*channel_urls, *(x['src'] for x in channels_remap))
257255

258256
if environment_file or environment:
259257
# set conda to be the user's conda (what is in the environment)

tests/test_fcp.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from __future__ import annotations
2+
3+
from contextlib import nullcontext
4+
5+
import pytest
6+
7+
from constructor.fcp import check_duplicates, exclude_packages
8+
9+
10+
class GenericObject:
11+
"""We use this for testing the check_duplicates function"""
12+
def __init__(self, name):
13+
self.name = name
14+
self.fn = 'filename.txt'
15+
16+
def __eq__(self, other):
17+
return self.name == other.name
18+
19+
20+
@pytest.mark.parametrize('values,expected_fails', (
21+
(
22+
(GenericObject('NameOne'), GenericObject('NameTwo'), GenericObject('NameTwo')), 1
23+
),
24+
(
25+
(GenericObject('NameOne'), GenericObject('NameTwo')), 0
26+
),
27+
(
28+
(GenericObject('NameOne'), GenericObject('NameTwo'), GenericObject('NameThree')), 0
29+
),
30+
))
31+
def test_check_duplicates(values: tuple[..., GenericObject], expected_fails: int):
32+
if expected_fails:
33+
context = pytest.raises(SystemExit)
34+
else:
35+
context = nullcontext()
36+
37+
with context:
38+
check_duplicates(values)
39+
40+
41+
@pytest.mark.parametrize('values,expected_value', (
42+
(
43+
(
44+
(GenericObject('NameOne'), GenericObject('NameTwo'), GenericObject('NameThree')),
45+
('NameThree',)
46+
),
47+
[GenericObject('NameOne'), GenericObject('NameTwo')]
48+
),
49+
(
50+
(
51+
(GenericObject('NameOne'), GenericObject('NameTwo'), GenericObject('NameThree')),
52+
('Not in list',)
53+
),
54+
False
55+
),
56+
))
57+
def test_exclude_packages(values: tuple[..., GenericObject], expected_value):
58+
if expected_value is False:
59+
context = pytest.raises(SystemExit)
60+
else:
61+
context = nullcontext()
62+
63+
with context:
64+
packages = exclude_packages(*values)
65+
assert packages == expected_value

0 commit comments

Comments
 (0)