code: def lint_missing_software_definition(self, rule):
      if (
          not rule.norun
          and not rule.is_handover
          and not rule.is_run
          and not (rule.conda_env or rule.container_img)
      ):
          if rule.env_modules:
              yield Lint(
                  title="Additionally specify a conda environment or container for each rule, environment modules are not enough",
                  body="While environment modules allow to document and deploy the required software on a certain "
                  "platform, they lock your workflow in there, disabling easy reproducibility on other machines "
                  "that don't have exactly the same environment modules. Hence env modules (which might be beneficial "
                  "in certain cluster environments), should allways be complemented with equivalent conda "
                  "environments.",
                  links=[links.package_management, links.containers],
              )
          else:
              yield Lint(
                  title="Specify a conda environment or container for each rule.",
                  body="This way, the used software for each specific step is documented, and "
                  "the workflow can be executed on any machine without prerequisites.",
                  links=[links.package_management, links.containers],
              )
  
file_path: snakemake/snakemake/linting/rules.py
imports: from itertools import chain
  import re
  import sys
  from snakemake.io import is_flagged
  from snakemake.linting import Linter, Lint, links, NAME_PATTERN
label_desc: Use image node_id 8 for calling the RuleLinter obj's underlying member method code with example usage: obj.lint_missing_software_definition(rule) without return types