@@ -36,14 +36,15 @@ def main_nf(
3636 * The module has a process label and it is among
3737 the standard ones.
3838 * If a ``meta`` map is defined as one of the modules
39- inputs it should be defined as one of the outputs ,
39+ inputs it should be defined as one of the emits ,
4040 and be correctly configured in the ``saveAs`` function.
4141 * The module script section should contain definitions
4242 of ``software`` and ``prefix``
4343 """
4444
4545 inputs : list [str ] = []
46- outputs : list [str ] = []
46+ emits : list [str ] = []
47+ topics : list [str ] = []
4748
4849 # Check if we have a patch file affecting the 'main.nf' file
4950 # otherwise read the lines directly from the module
@@ -132,8 +133,9 @@ def main_nf(
132133 line = joint_tuple
133134 inputs .extend (_parse_input (module , line ))
134135 if state == "output" and not _is_empty (line ):
135- outputs += _parse_output (module , line )
136- outputs = list (set (outputs )) # remove duplicate 'meta's
136+ emits += _parse_output_emits (module , line )
137+ emits = list (set (emits )) # remove duplicate 'meta's
138+ topics += _parse_output_topics (module , line )
137139 if state == "when" and not _is_empty (line ):
138140 when_lines .append (line )
139141 if state == "script" and not _is_empty (line ):
@@ -144,7 +146,7 @@ def main_nf(
144146 exec_lines .append (line )
145147
146148 # Check that we have required sections
147- if not len (outputs ):
149+ if not len (emits ):
148150 module .failed .append (("main_nf" , "main_nf_script_outputs" , "No process 'output' block found" , module .main_nf ))
149151 else :
150152 module .passed .append (("main_nf" , "main_nf_script_outputs" , "Process 'output' block found" , module .main_nf ))
@@ -192,8 +194,8 @@ def main_nf(
192194 if inputs :
193195 if "meta" in inputs :
194196 module .has_meta = True
195- if outputs :
196- if "meta" in outputs :
197+ if emits :
198+ if "meta" in emits :
197199 module .passed .append (
198200 (
199201 "main_nf" ,
@@ -213,22 +215,43 @@ def main_nf(
213215 )
214216
215217 # Check that a software version is emitted
216- if outputs :
217- if "versions" in outputs :
218+ if topics :
219+ if "versions" in topics :
218220 module .passed .append (
219- ("main_nf" , "main_nf_version_emitted " , "Module emits software version " , module .main_nf )
221+ ("main_nf" , "main_nf_version_topic " , "Module emits software versions as topic " , module .main_nf )
220222 )
221223 else :
224+ module .warned .append (
225+ ("main_nf" , "main_nf_version_topic" , "Module does not emit software versions as topic" , module .main_nf )
226+ )
227+
228+ if emits :
229+ topic_versions_amount = sum (1 for t in topics if t == "versions" )
230+ emit_versions_amount = sum (1 for e in emits if e .startswith ("versions" ))
231+ if topic_versions_amount == emit_versions_amount :
232+ module .passed .append (
233+ ("main_nf" , "main_nf_version_emit" , "Module emits each software version" , module .main_nf )
234+ )
235+ elif "versions" in emits :
222236 module .warned .append (
223237 (
224238 "main_nf" ,
225- "main_nf_version_emitted" ,
226- "Module does not emit software version" ,
239+ "main_nf_version_emit" ,
240+ "Module emits software versions YAML, please update this to topics output" ,
241+ module .main_nf ,
242+ )
243+ )
244+ else :
245+ module .failed .append (
246+ (
247+ "main_nf" ,
248+ "main_nf_version_emit" ,
249+ "Module does not have an `emit:` and `topic:` for each software version" ,
227250 module .main_nf ,
228251 )
229252 )
230253
231- return inputs , outputs
254+ return inputs , emits
232255
233256
234257def check_script_section (self , lines ):
@@ -238,14 +261,6 @@ def check_script_section(self, lines):
238261 """
239262 script = "" .join (lines )
240263
241- # check that process name is used for `versions.yml`
242- if re .search (r"\$\{\s*task\.process\s*\}" , script ):
243- self .passed .append (("main_nf" , "main_nf_version_script" , "Process name used for versions.yml" , self .main_nf ))
244- else :
245- self .warned .append (
246- ("main_nf" , "main_nf_version_script" , "Process name not used for versions.yml" , self .main_nf )
247- )
248-
249264 # check for prefix (only if module has a meta map as input)
250265 if self .has_meta :
251266 if re .search (r"\s*prefix\s*=\s*task.ext.prefix" , script ):
@@ -705,16 +720,43 @@ def _parse_input(self, line_raw):
705720 return inputs
706721
707722
708- def _parse_output (self , line ) :
723+ def _parse_output_emits (self , line : str ) -> list [ str ] :
709724 output = []
710725 if "meta" in line :
711726 output .append ("meta" )
712- if "emit:" not in line :
713- self .failed .append (("main_nf" , "missing_emit" , f"Missing emit statement: { line .strip ()} " , self .main_nf ))
727+ emit_regex = re .search (r"^.*emit:\s*([^,\s]*)" , line )
728+ if not emit_regex :
729+ self .failed .append (("missing_emit" , f"Missing emit statement: { line .strip ()} " , self .main_nf ))
714730 else :
715- output .append (line .split ("emit:" )[1 ].strip ())
716- self .passed .append (("main_nf" , "missing_emit" , f"Emit statement found: { line .strip ()} " , self .main_nf ))
731+ output .append (emit_regex .group (1 ).strip ())
732+ return output
733+
717734
735+ def _parse_output_topics (self , line : str ) -> list [str ]:
736+ output = []
737+ if "meta" in line :
738+ output .append ("meta" )
739+ topic_regex = re .search (r"^.*topic:\s*([^,\s]*)" , line )
740+ if topic_regex :
741+ topic_name = topic_regex .group (1 ).strip ()
742+ output .append (topic_name )
743+ if topic_name == "versions" :
744+ if not re .search (r'tuple\s+val\("\${\s*task\.process\s*}"\),\s*val\(.*\),\s*eval\(.*\)' , line ):
745+ self .failed .append (
746+ (
747+ "wrong_version_output" ,
748+ 'Versions topic output is not correctly formatted, expected `tuple val("${task.process}"), val(\' <tool>\' ), eval("<version_command>")`' ,
749+ self .main_nf ,
750+ )
751+ )
752+ if not re .search (r"emit:\s*versions_[\d\w]+" , line ):
753+ self .failed .append (
754+ (
755+ "wrong_version_emit" ,
756+ "Version emit should follow the format `versions_<tool_or_package>`, e.g.: `versions_samtools`, `versions_gatk4`" ,
757+ self .main_nf ,
758+ )
759+ )
718760 return output
719761
720762
0 commit comments