Skip to content

Commit ade688f

Browse files
authored
Fix extras require issue (#326)
* black * issue to be fixed: extras_require is a dictionary, not a list * fix extras_require issue
1 parent ea6fbc6 commit ade688f

File tree

5 files changed

+122
-26
lines changed

5 files changed

+122
-26
lines changed

docs/source/conf.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,23 @@
1717

1818
# -- Project information -----------------------------------------------------
1919

20-
project = 'Grayskull'
21-
copyright = '2022, Grayskull Developers.'
22-
author = 'Grayskull Developers'
20+
project = "Grayskull"
21+
copyright = "2022, Grayskull Developers."
22+
author = "Grayskull Developers"
2323

2424
# The full version, including alpha/beta/rc tags
25-
release = '1.1.0'
25+
release = "1.1.0"
2626

2727

2828
# -- General configuration ---------------------------------------------------
2929

3030
# Add any Sphinx extension module names here, as strings. They can be
3131
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
3232
# ones.
33-
extensions = [
34-
]
33+
extensions = []
3534

3635
# Add any paths that contain templates here, relative to this directory.
37-
templates_path = ['_templates']
36+
templates_path = ["_templates"]
3837

3938
# List of patterns, relative to source directory, that match files and
4039
# directories to ignore when looking for source files.
@@ -47,9 +46,9 @@
4746
# The theme to use for HTML and HTML Help pages. See the documentation for
4847
# a list of builtin themes.
4948
#
50-
html_theme = 'furo'
49+
html_theme = "furo"
5150

5251
# Add any paths that contain custom static files (such as style sheets) here,
5352
# relative to this directory. They are copied after the builtin static files,
5453
# so a file named "default.css" will overwrite the builtin "default.css".
55-
html_static_path = ['_static']
54+
html_static_path = ["_static"]

grayskull/strategy/py_base.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
from grayskull.utils import (
2323
PyVer,
2424
get_vendored_dependencies,
25+
merge_dict_of_lists_item,
26+
merge_list_item,
2527
origin_is_github,
2628
sha256_checksum,
2729
)
@@ -256,23 +258,14 @@ def merge_sdist_metadata(setup_py: dict, setup_cfg: dict) -> dict:
256258
if key not in result:
257259
result[key] = value
258260

259-
def get_full_list(sec_key: str) -> List:
260-
if sec_key not in setup_py:
261-
return setup_cfg.get(sec_key, [])
262-
cfg_val = set(setup_cfg.get(sec_key, []))
263-
result_val = set(result.get(sec_key, []))
264-
return list(cfg_val.union(result_val))
265-
266-
if "install_requires" in result:
267-
result["install_requires"] = get_full_list("install_requires")
268-
if "extras_require" in result:
269-
result["extras_require"] = get_full_list("extras_require")
270-
if "setup_requires" in result:
271-
result["setup_requires"] = get_full_list("setup_requires")
272-
if "setuptools-scm" in result["setup_requires"]:
273-
result["setup_requires"].remove("setuptools-scm")
274-
if "compilers" in result:
275-
result["compilers"] = get_full_list("compilers")
261+
merge_list_item(result, setup_cfg, "install_requires")
262+
merge_list_item(result, setup_cfg, "setup_requires")
263+
merge_list_item(result, setup_cfg, "compilers")
264+
merge_dict_of_lists_item(result, setup_cfg, "extras_require")
265+
266+
if "setuptools-scm" in result.get("setup_requires", []):
267+
result["setup_requires"].remove("setuptools-scm")
268+
276269
return result
277270

278271

grayskull/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,19 @@ def _clean_yaml(recipe, all_obj_to_delete=None):
235235
value_to_delete = _clean_yaml(value)
236236
all_obj_to_delete.extend(value_to_delete)
237237
return all_obj_to_delete
238+
239+
240+
def merge_list_item(destination: dict, add: dict, key: str) -> None:
241+
lst = set(destination.get(key, []))
242+
lst |= set(add.get(key, []))
243+
if lst:
244+
destination[key] = list(lst)
245+
246+
247+
def merge_dict_of_lists_item(destination: dict, add: dict, key: str) -> None:
248+
sub_destination = destination.get(key, {})
249+
sub_add = add.get(key, {})
250+
for sub_key in set(sub_destination) | set(sub_add):
251+
merge_list_item(sub_destination, sub_add, sub_key)
252+
if sub_destination:
253+
destination[key] = sub_destination

tests/test_pypi.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,33 @@ def test_get_extra_from_requires_dist():
122122
]
123123

124124

125+
def test_get_extra_requirements():
126+
config = Configuration(name="pypushflow")
127+
data = get_sdist_metadata(
128+
"https://pypi.io/packages/source/p/pypushflow/pypushflow-0.3.0rc2.tar.gz",
129+
config,
130+
)
131+
received = {extra: set(lst) for extra, lst in data["extras_require"].items()}
132+
expected = {
133+
"mx": {"pymongo >=4, <5"},
134+
"test": {
135+
"mongita >=1, <2",
136+
"pytest >=7, <8",
137+
"psutil >=5.8, <6",
138+
"pytest-subtests >=0.4, <1",
139+
},
140+
"dev": {
141+
"pytest >=7, <8",
142+
"black >=22, <23",
143+
"psutil >=5.8, <6",
144+
"flake8 >=4, <5",
145+
"mongita >=1, <2",
146+
"pytest-subtests >=0.4, <1",
147+
},
148+
}
149+
assert received == expected
150+
151+
125152
def test_get_all_selectors_pypi(recipe_config):
126153
_, config = recipe_config
127154
config.version = "5.3.1"

tests/test_utils.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
get_all_modules_imported_script,
88
get_std_modules,
99
get_vendored_dependencies,
10+
merge_dict_of_lists_item,
11+
merge_list_item,
1012
origin_is_local_sdist,
1113
)
1214

@@ -57,3 +59,62 @@ def test_origin_is_not_local_sdist_file(tmp_path):
5759
)
5860
def test_origin_is_not_local_sdist_filename(filename):
5961
assert not origin_is_local_sdist(filename)
62+
63+
64+
def test_merge_lists_item():
65+
destination = {}
66+
add = {}
67+
merge_list_item(destination, add, "name")
68+
assert destination == {}
69+
70+
destination = {"name": [1]}
71+
add = {}
72+
merge_list_item(destination, add, "name")
73+
destination = {key: set(lst) for key, lst in destination.items()}
74+
assert destination == {"name": {1}}
75+
76+
destination = {}
77+
add = {"name": [2]}
78+
merge_list_item(destination, add, "name")
79+
destination = {key: set(lst) for key, lst in destination.items()}
80+
assert destination == {"name": {2}}
81+
82+
destination = {"name": [1]}
83+
add = {"name": [2]}
84+
merge_list_item(destination, add, "name")
85+
destination = {key: set(lst) for key, lst in destination.items()}
86+
assert destination == {"name": {1, 2}}
87+
88+
89+
def test_merge_dict_of_lists_item():
90+
destination = {}
91+
add = {}
92+
merge_dict_of_lists_item(destination, add, "name")
93+
assert destination == {}
94+
95+
destination = {"name": {"sub_name": [1]}}
96+
add = {}
97+
merge_dict_of_lists_item(destination, add, "name")
98+
for key in destination:
99+
destination[key] = {
100+
sub_key: set(lst) for sub_key, lst in destination[key].items()
101+
}
102+
assert destination == {"name": {"sub_name": {1}}}
103+
104+
destination = {}
105+
add = {"name": {"sub_name": [2]}}
106+
merge_dict_of_lists_item(destination, add, "name")
107+
for key in destination:
108+
destination[key] = {
109+
sub_key: set(lst) for sub_key, lst in destination[key].items()
110+
}
111+
assert destination == {"name": {"sub_name": {2}}}
112+
113+
destination = {"name": {"sub_name": [1]}}
114+
add = {"name": {"sub_name": [2]}}
115+
merge_dict_of_lists_item(destination, add, "name")
116+
for key in destination:
117+
destination[key] = {
118+
sub_key: set(lst) for sub_key, lst in destination[key].items()
119+
}
120+
assert destination == {"name": {"sub_name": {1, 2}}}

0 commit comments

Comments
 (0)