Skip to content

Commit dd17aa7

Browse files
authored
fix!: also find tests under outputs, ensure all outputs have tests, ensure outputs names are different from package name (#1057)
This pull request is motivated by trying to add a subpackage to an existing package and trying to get the syntax right: bioconda/bioconda-recipes#58141 I think I have to add both the main and the subpackage under an `outputs:` section, and the linter then complains that it doesn't find any global `test:` section. So this PR makes the linter go through each subpackage if an `outputs:` section exists, and checks whether all of them have a valid `test:` section specified.
1 parent 575bc37 commit dd17aa7

File tree

4 files changed

+135
-12
lines changed

4 files changed

+135
-12
lines changed

bioconda_utils/lint/check_completeness.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
import os
7-
from . import LintCheck, ERROR, WARNING, INFO
7+
from . import LintCheck, ERROR, WARNING, INFO, _recipe
88

99

1010
class missing_build_number(LintCheck):
@@ -81,19 +81,44 @@ class missing_tests(LintCheck):
8181
and/or any file named ``run_test.py`, ``run_test.sh`` or
8282
``run_test.pl`` executing tests.
8383
84+
You can either add the test section on the top level of
85+
your meta.yaml file; or if you use an ``outputs:`` section
86+
to specify multiple outputs, add a test to each of your
87+
``outputs:`` entries.
8488
"""
8589
test_files = ['run_test.py', 'run_test.sh', 'run_test.pl']
8690

8791
def check_recipe(self, recipe):
8892
if any(os.path.exists(os.path.join(recipe.dir, f))
89-
for f in self.test_files):
93+
for f in self.test_files):
9094
return
91-
if recipe.get('test/commands', '') or recipe.get('test/imports', ''):
92-
return
93-
if recipe.get('test', False) is not False:
94-
self.message(section='test')
95+
# if multiple `outputs:` are specified, we check that
96+
# all subpackages have `test:` specified, but ignore
97+
# top-level tests, as top-level package outputs will
98+
# become incompatible with multiple `outputs:` in the
99+
# future, see:
100+
# https://conda.org/learn/ceps/cep-0014/#outputs-section
101+
if recipe.get('outputs', ''):
102+
packages = recipe.get('outputs')
95103
else:
96-
self.message()
104+
packages = [ recipe, ]
105+
# can't use the Recipe.get function, as we might have plain dicts
106+
# here; so we need to go one level of the resulting dicts at
107+
# a time and check that all of them have a test specified
108+
tests_specified = [
109+
t.get('commands', '') or t.get('imports', '')
110+
for t in [ p.get('test', {}) for p in packages ]
111+
]
112+
if all(tests_specified):
113+
return
114+
for i in range(len(packages)):
115+
if not tests_specified[i]:
116+
if not isinstance(packages[i], _recipe.Recipe) and packages[i].get(f'outputs/{i}/test', ''):
117+
self.message(section=f'outputs/{i}/test')
118+
elif packages[i].get('test', ''):
119+
self.message(section='test')
120+
else:
121+
self.message()
97122

98123

99124
class missing_hash(LintCheck):

bioconda_utils/lint/check_policy.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,25 @@ def check_deps(self, deps):
124124
self.message()
125125

126126

127+
class outputs_name_same_as_package_name(LintCheck):
128+
"""Output names must differ from main package name
129+
130+
If multiple outputs are specified, their names must be different from the
131+
main package name.
132+
133+
This enforces accepted CEP 0014: https://conda.org/learn/ceps/cep-0014/#outputs-section
134+
And it prevents hard to debug issues: https://github.com/conda/conda-build/pull/5767
135+
136+
"""
137+
def check_recipe(self, recipe):
138+
name = recipe.get('package', {}).get('name', '')
139+
outputs = recipe.get('outputs', '')
140+
if outputs:
141+
for o in outputs:
142+
if o.get('name', '') == name:
143+
self.message()
144+
145+
127146
class version_starts_with_v(LintCheck):
128147
"""The version string should not start with a "v" character
129148

test/conftest.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,23 @@ def recipe_dir(recipes_folder: py.path.local, tmpdir: py.path.local,
139139
for remove in utils.ensure_list(case['remove']):
140140
path = remove.split('/')
141141
cont = recipe
142+
select_by_name = False
142143
for p in path[:-1]:
143-
cont = cont[p]
144+
if select_by_name:
145+
for subpackage in cont:
146+
if subpackage['name'] == p:
147+
cont = subpackage
148+
select_by_name = False
149+
else:
150+
cont = cont.get(p, {})
151+
if p == "outputs":
152+
select_by_name = True
144153
if isinstance(cont, list):
145154
for n in range(len(cont)):
146155
del cont[n][path[-1]]
147156
else:
148-
del cont[path[-1]]
157+
if cont.get(path[-1], ""):
158+
del cont[path[-1]]
149159
if 'add' in case:
150160
dict_merge(recipe, case['add'])
151161

test/lint_cases.yaml

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,56 @@ setup:
5252
license: BSD
5353
home: https://elsewhere
5454
summary: the_summary
55+
meta:
56+
folder: meta_package
57+
meta.yaml:
58+
package:
59+
name: meta_package
60+
version: 0.1
61+
source:
62+
- url: https://somewhere
63+
sha256: 123
64+
- url: https://elsewhere
65+
sha256: abc
66+
build:
67+
noarch: True
68+
number: 0
69+
run_exports:
70+
# add a run export
71+
# (note that jinja templating as in reality is not
72+
# supported by our test system to the same
73+
# extend as in conda build)
74+
- "{{ pin_subpackage('meta_package') }}"
75+
outputs:
76+
- name: meta_one
77+
build:
78+
noarch: True
79+
run_exports:
80+
# add a run export
81+
# (note that jinja templating as in reality is not
82+
# supported by our test system to the same
83+
# extend as in conda build)
84+
- "{{ pin_subpackage('meta_one') }}"
85+
test:
86+
commands:
87+
- do nothing
88+
- name: meta_two
89+
build:
90+
noarch: True
91+
number: 0
92+
run_exports:
93+
# add a run export
94+
# (note that jinja templating as in reality is not
95+
# supported by our test system to the same
96+
# extend as in conda build)
97+
- "{{ pin_subpackage('meta_two') }}"
98+
test:
99+
imports:
100+
- no imports to see here
101+
about:
102+
license: MIT
103+
home: https://elsewhere
104+
summary: another_summary
55105
repodata:
56106
bioconda:
57107
one:
@@ -60,6 +110,8 @@ setup:
60110
- version: 0.0.1
61111
four:
62112
- version: 0.0.1
113+
meta_package:
114+
- version: 0.0.1
63115
conda-forge:
64116
three:
65117
- version: 1.0
@@ -123,11 +175,14 @@ tests:
123175
add: { about: { license: "" } }
124176
expect: missing_license
125177
- name: missing_tests
126-
remove: test
178+
remove:
179+
- test
180+
- outputs/meta_one/test
127181
expect: missing_tests
128182
- name: missing_tests_empty_section
129183
remove:
130184
- test/commands
185+
- outputs/meta_two/test/imports
131186
expect: missing_tests
132187
- name: missing_tests_but_runtest_py
133188
remove: test
@@ -142,7 +197,10 @@ tests:
142197
add_files:
143198
run_test.pl: ""
144199
- name: missing_tests_but_runtst_sh
145-
remove: test
200+
remove:
201+
- test
202+
- outputs/meta_one/test
203+
- outputs/meta_two/test
146204
add_files:
147205
run_tst.sh: ""
148206
expect: missing_tests
@@ -364,12 +422,22 @@ tests:
364422
- name: build_number_needs_bump
365423
expect: build_number_needs_bump
366424
add: { package: { version: 0.0.1 } }
425+
- name: outputs_name_same_as_package_name
426+
expect: outputs_name_same_as_package_name
427+
add:
428+
outputs:
429+
- name: "meta_package"
430+
- name: "one"
431+
- name: "two"
432+
extra:
433+
skip-lints:
434+
- missing_tests
367435
- name: version_starts_with_v
368436
expect: version_starts_with_v
369437
add: { package: { version: "v0.1" } }
370438
- name: in_other_channels
371439
expect: in_other_channels
372-
repodata: { conda-forge: { one: [{ version: 0.1 }], two: [version: 0.1] } }
440+
repodata: { conda-forge: { one: [{ version: 0.1 }], two: [version: 0.1], meta_package: [version: 0.1] } }
373441
- name: long_summary
374442
expect: long_summary
375443
add:
@@ -383,6 +451,7 @@ tests:
383451
blacklist: |
384452
recipes/one
385453
recipes/two
454+
recipes/meta_package
386455
config:
387456
blacklists:
388457
- blacklist

0 commit comments

Comments
 (0)