prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Bad dependencies kill entire extension build
  [SlicerVideoCamera name change](https://github.com/Slicer/ExtensionsIndex/commit/93d1942ed51a5c576f477dab77df9529ce788754) introduced this [bug](https://github.com/Slicer/ExtensionsIndex/commit/4181b49933cca4bf1420d1b8f7b54017bbfe131c) where an extension had a non-existent dependency.
  
  Resulting [CMake Error](https://slicer.cdash.org/build/2225046/configure) terminated the whole build process.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `scripts/check_description_files.py`
  Content:
  ```
  1 #!/usr/bin/env python
  2 
  3 """
  4 Python 3.x CLI for validating extension description files.
  5 """
  6 
  7 import argparse
  8 import os
  9 import sys
  10 import textwrap
  11 import urllib.parse as urlparse
  12 
  13 from functools import wraps
  14 
  15 
  16 class ExtensionCheckError(RuntimeError):
  17     """Exception raised when a particular extension check failed.
  18     """
  19     def __init__(self, extension_name, check_name, details):
  20         self.extension_name = extension_name
  21         self.check_name = check_name
  22         self.details = details
  23 
  24     def __str__(self):
  25         return self.details
  26 
  27 
  28 def require_metadata_key(metadata_key):
  29     check_name = "require_metadata_key"
  30 
  31     def dec(fun):
  32         @wraps(fun)
  33         def wrapped(*args, **kwargs):
  34             extension_name = args[0]
  35             metadata = args[1]
  36             if metadata_key not in metadata.keys():
  37                 raise ExtensionCheckError(extension_name, check_name, "%s key is missing" % metadata_key)
  38             return fun(*args, **kwargs)
  39         return wrapped
  40     return dec
  41 
  42 
  43 def parse_s4ext(ext_file_path):
  44     """Parse a Slicer extension description file.
  45     :param ext_file_path: Path to a Slicer extension description file.
  46     :return: Dictionary of extension metadata.
  47     """
  48     ext_metadata = {}
  49     with open(ext_file_path) as ext_file:
  50         for line in ext_file:
  51             if not line.strip() or line.startswith("#"):
  52                 continue
  53             fields = [field.strip() for field in line.split(' ', 1)]
  54             assert(len(fields) <= 2)
  55             ext_metadata[fields[0]] = fields[1] if len(fields) == 2 else None
  56     return ext_metadata
  57 
  58 
  59 @require_metadata_key("scmurl")
  60 def check_scmurl_syntax(extension_name, metadata):
  61     check_name = "check_scmurl_syntax"
  62 
  63     if "://" not in metadata["scmurl"]:
  64         raise ExtensionCheckError(extension_name, check_name, "scmurl do not match scheme://host/path")
  65 
  66     supported_schemes = ["git", "https", "svn"]
  67     scheme = urlparse.urlsplit(metadata["scmurl"]).scheme
  68     if scheme not in supported_schemes:
  69         raise ExtensionCheckError(
  70             extension_name, check_name,
  71             "scmurl scheme is '%s' but it should by any of %s" % (scheme, supported_schemes))
  72 
  73 
  74 @require_metadata_key("scmurl")
  75 @require_metadata_key("scm")
  76 def check_git_repository_name(extension_name, metadata):
  77     """See https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ#Should_the_name_of_the_source_repository_match_the_name_of_the_extension_.3F
  78     """
  79     check_name = "check_git_repository_name"
  80 
  81     if metadata["scm"] != "git":
  82         return
  83 
  84     repo_name = os.path.splitext(urlparse.urlsplit(metadata["scmurl"]).path.split("/")[-1])[0]
  85 
  86     if not repo_name.startswith("Slicer"):
  87 
  88         variations = [prefix + repo_name for prefix in ["Slicer-", "Slicer_", "SlicerExtension-", "SlicerExtension_"]]
  89 
  90         raise ExtensionCheckError(
  91             extension_name, check_name,
  92             textwrap.dedent("""
  93             extension repository name is '%s'. Please, consider changing it to 'Slicer%s' or any of
  94             these variations %s.
  95             """ % (
  96                 repo_name, repo_name, variations)))
  97 
  98 
  99 def main():
  100     parser = argparse.ArgumentParser(
  101         description='Validate extension description files.')
  102     parser.add_argument(
  103         "--check-git-repository-name", action="store_true",
  104         help="Check extension git repository name. Disabled by default.")
  105     parser.add_argument("/path/to/description.s4ext", nargs='*')
  106     args = parser.parse_args()
  107 
  108     checks = []
  109 
  110     if args.check_git_repository_name:
  111         checks.append(check_git_repository_name)
  112 
  113     if not checks:
  114         checks = [
  115             check_scmurl_syntax,
  116         ]
  117 
  118     total_failure_count = 0
  119 
  120     file_paths = getattr(args, "/path/to/description.s4ext")
  121     for file_path in file_paths:
  122         extension_name = os.path.splitext(os.path.basename(file_path))[0]
  123 
  124         failures = []
  125  
  126         metadata = parse_s4ext(file_path)
  127         for check in checks:
  128             try:
  129                 check(extension_name, metadata)
  130             except ExtensionCheckError as exc:
  131                 failures.append(str(exc))
  132 
  133         if failures:
  134             total_failure_count += len(failures)
  135             print("%s.s4ext" % extension_name)
  136             for failure in set(failures):
  137                 print("  %s" % failure)
  138 
  139     print("Checked %d description files: Found %d errors" % (len(file_paths), total_failure_count))
  140     sys.exit(total_failure_count)
  141 
  142 
  143 if __name__ == "__main__":
  144     main()
  145
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/scripts/check_description_files.py b/scripts/check_description_files.py
  --- a/scripts/check_description_files.py
  +++ b/scripts/check_description_files.py
  @@ -95,6 +95,38 @@
               """ % (
                   repo_name, repo_name, variations)))
   
  +def check_dependencies(directory):
  +    import os
  +    required_extensions = {}  # for each extension it contains a list of extensions that require it
  +    available_extensions = []
  +    for filename in os.listdir(directory):
  +        f = os.path.join(directory, filename)
  +        if not os.path.isfile(f):
  +            continue
  +        extension_name = os.path.splitext(os.path.basename(filename))[0]
  +        available_extensions.append(extension_name)
  +        extension_description = parse_s4ext(f)
  +        if 'depends' not in extension_description:
  +            continue
  +        dependencies = extension_description['depends'].split(' ')
  +        for dependency in dependencies:
  +            if dependency == 'NA':
  +                # special value, just a placeholder that must be ignored
  +                continue
  +            if dependency in required_extensions:
  +                required_extensions[dependency].append(extension_name)
  +            else:
  +                required_extensions[dependency] = [extension_name]
  +    print(f"Checked dependency between {len(available_extensions)} extensions.")
  +    error_count = 0
  +    for extension in required_extensions:
  +        if extension in available_extensions:
  +            # required extension is found
  +            continue
  +        required_by_extensions = ', '.join(required_extensions[extension])
  +        print(f"{extension} extension is not found. It is required by extension: {required_by_extensions}.")
  +        error_count += 1
  +    return error_count
   
   def main():
       parser = argparse.ArgumentParser(
  @@ -102,6 +134,7 @@
       parser.add_argument(
           "--check-git-repository-name", action="store_true",
           help="Check extension git repository name. Disabled by default.")
  +    parser.add_argument("-d", "--check-dependencies", help="Check all extension dsecription files in the provided folder.")
       parser.add_argument("/path/to/description.s4ext", nargs='*')
       args = parser.parse_args()
   
  @@ -136,7 +169,13 @@
               for failure in set(failures):
                   print("  %s" % failure)
   
  -    print("Checked %d description files: Found %d errors" % (len(file_paths), total_failure_count))
  +    print(f"Checked content of {len(file_paths)} description files.")
  +
  +
  +    if args.check_dependencies:
  +        total_failure_count += check_dependencies(args.check_dependencies)
  +
  +    print(f"Total errors found in extension descriptions: {total_failure_count}")
       sys.exit(total_failure_count)
  
verification_info: {"golden_diff": "diff --git a/scripts/check_description_files.py b/scripts/check_description_files.py\n--- a/scripts/check_description_files.py\n+++ b/scripts/check_description_files.py\n@@ -95,6 +95,38 @@\n             \"\"\" % (\n                 repo_name, repo_name, variations)))\n \n+def check_dependencies(directory):\n+    import os\n+    required_extensions = {}  # for each extension it contains a list of extensions that require it\n+    available_extensions = []\n+    for filename in os.listdir(directory):\n+        f = os.path.join(directory, filename)\n+        if not os.path.isfile(f):\n+            continue\n+        extension_name = os.path.splitext(os.path.basename(filename))[0]\n+        available_extensions.append(extension_name)\n+        extension_description = parse_s4ext(f)\n+        if 'depends' not in extension_description:\n+            continue\n+        dependencies = extension_description['depends'].split(' ')\n+        for dependency in dependencies:\n+            if dependency == 'NA':\n+                # special value, just a placeholder that must be ignored\n+                continue\n+            if dependency in required_extensions:\n+                required_extensions[dependency].append(extension_name)\n+            else:\n+                required_extensions[dependency] = [extension_name]\n+    print(f\"Checked dependency between {len(available_extensions)} extensions.\")\n+    error_count = 0\n+    for extension in required_extensions:\n+        if extension in available_extensions:\n+            # required extension is found\n+            continue\n+        required_by_extensions = ', '.join(required_extensions[extension])\n+        print(f\"{extension} extension is not found. It is required by extension: {required_by_extensions}.\")\n+        error_count += 1\n+    return error_count\n \n def main():\n     parser = argparse.ArgumentParser(\n@@ -102,6 +134,7 @@\n     parser.add_argument(\n         \"--check-git-repository-name\", action=\"store_true\",\n         help=\"Check extension git repository name. Disabled by default.\")\n+    parser.add_argument(\"-d\", \"--check-dependencies\", help=\"Check all extension dsecription files in the provided folder.\")\n     parser.add_argument(\"/path/to/description.s4ext\", nargs='*')\n     args = parser.parse_args()\n \n@@ -136,7 +169,13 @@\n             for failure in set(failures):\n                 print(\"  %s\" % failure)\n \n-    print(\"Checked %d description files: Found %d errors\" % (len(file_paths), total_failure_count))\n+    print(f\"Checked content of {len(file_paths)} description files.\")\n+\n+\n+    if args.check_dependencies:\n+        total_failure_count += check_dependencies(args.check_dependencies)\n+\n+    print(f\"Total errors found in extension descriptions: {total_failure_count}\")\n     sys.exit(total_failure_count)\n", "issue": "Bad dependencies kill entire extension build\n[SlicerVideoCamera name change](https://github.com/Slicer/ExtensionsIndex/commit/93d1942ed51a5c576f477dab77df9529ce788754) introduced this [bug](https://github.com/Slicer/ExtensionsIndex/commit/4181b49933cca4bf1420d1b8f7b54017bbfe131c) where an extension had a non-existent dependency.\r\n\r\nResulting [CMake Error](https://slicer.cdash.org/build/2225046/configure) terminated the whole build process.\n", "before_files": [{"content": "#!/usr/bin/env python\n\n\"\"\"\nPython 3.x CLI for validating extension description files.\n\"\"\"\n\nimport argparse\nimport os\nimport sys\nimport textwrap\nimport urllib.parse as urlparse\n\nfrom functools import wraps\n\n\nclass ExtensionCheckError(RuntimeError):\n    \"\"\"Exception raised when a particular extension check failed.\n    \"\"\"\n    def __init__(self, extension_name, check_name, details):\n        self.extension_name = extension_name\n        self.check_name = check_name\n        self.details = details\n\n    def __str__(self):\n        return self.details\n\n\ndef require_metadata_key(metadata_key):\n    check_name = \"require_metadata_key\"\n\n    def dec(fun):\n        @wraps(fun)\n        def wrapped(*args, **kwargs):\n            extension_name = args[0]\n            metadata = args[1]\n            if metadata_key not in metadata.keys():\n                raise ExtensionCheckError(extension_name, check_name, \"%s key is missing\" % metadata_key)\n            return fun(*args, **kwargs)\n        return wrapped\n    return dec\n\n\ndef parse_s4ext(ext_file_path):\n    \"\"\"Parse a Slicer extension description file.\n    :param ext_file_path: Path to a Slicer extension description file.\n    :return: Dictionary of extension metadata.\n    \"\"\"\n    ext_metadata = {}\n    with open(ext_file_path) as ext_file:\n        for line in ext_file:\n            if not line.strip() or line.startswith(\"#\"):\n                continue\n            fields = [field.strip() for field in line.split(' ', 1)]\n            assert(len(fields) <= 2)\n            ext_metadata[fields[0]] = fields[1] if len(fields) == 2 else None\n    return ext_metadata\n\n\n@require_metadata_key(\"scmurl\")\ndef check_scmurl_syntax(extension_name, metadata):\n    check_name = \"check_scmurl_syntax\"\n\n    if \"://\" not in metadata[\"scmurl\"]:\n        raise ExtensionCheckError(extension_name, check_name, \"scmurl do not match scheme://host/path\")\n\n    supported_schemes = [\"git\", \"https\", \"svn\"]\n    scheme = urlparse.urlsplit(metadata[\"scmurl\"]).scheme\n    if scheme not in supported_schemes:\n        raise ExtensionCheckError(\n            extension_name, check_name,\n            \"scmurl scheme is '%s' but it should by any of %s\" % (scheme, supported_schemes))\n\n\n@require_metadata_key(\"scmurl\")\n@require_metadata_key(\"scm\")\ndef check_git_repository_name(extension_name, metadata):\n    \"\"\"See https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ#Should_the_name_of_the_source_repository_match_the_name_of_the_extension_.3F\n    \"\"\"\n    check_name = \"check_git_repository_name\"\n\n    if metadata[\"scm\"] != \"git\":\n        return\n\n    repo_name = os.path.splitext(urlparse.urlsplit(metadata[\"scmurl\"]).path.split(\"/\")[-1])[0]\n\n    if not repo_name.startswith(\"Slicer\"):\n\n        variations = [prefix + repo_name for prefix in [\"Slicer-\", \"Slicer_\", \"SlicerExtension-\", \"SlicerExtension_\"]]\n\n        raise ExtensionCheckError(\n            extension_name, check_name,\n            textwrap.dedent(\"\"\"\n            extension repository name is '%s'. Please, consider changing it to 'Slicer%s' or any of\n            these variations %s.\n            \"\"\" % (\n                repo_name, repo_name, variations)))\n\n\ndef main():\n    parser = argparse.ArgumentParser(\n        description='Validate extension description files.')\n    parser.add_argument(\n        \"--check-git-repository-name\", action=\"store_true\",\n        help=\"Check extension git repository name. Disabled by default.\")\n    parser.add_argument(\"/path/to/description.s4ext\", nargs='*')\n    args = parser.parse_args()\n\n    checks = []\n\n    if args.check_git_repository_name:\n        checks.append(check_git_repository_name)\n\n    if not checks:\n        checks = [\n            check_scmurl_syntax,\n        ]\n\n    total_failure_count = 0\n\n    file_paths = getattr(args, \"/path/to/description.s4ext\")\n    for file_path in file_paths:\n        extension_name = os.path.splitext(os.path.basename(file_path))[0]\n\n        failures = []\n \n        metadata = parse_s4ext(file_path)\n        for check in checks:\n            try:\n                check(extension_name, metadata)\n            except ExtensionCheckError as exc:\n                failures.append(str(exc))\n\n        if failures:\n            total_failure_count += len(failures)\n            print(\"%s.s4ext\" % extension_name)\n            for failure in set(failures):\n                print(\"  %s\" % failure)\n\n    print(\"Checked %d description files: Found %d errors\" % (len(file_paths), total_failure_count))\n    sys.exit(total_failure_count)\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "scripts/check_description_files.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\n\"\"\"\nPython 3.x CLI for validating extension description files.\n\"\"\"\n\nimport argparse\nimport os\nimport sys\nimport textwrap\nimport urllib.parse as urlparse\n\nfrom functools import wraps\n\n\nclass ExtensionCheckError(RuntimeError):\n    \"\"\"Exception raised when a particular extension check failed.\n    \"\"\"\n    def __init__(self, extension_name, check_name, details):\n        self.extension_name = extension_name\n        self.check_name = check_name\n        self.details = details\n\n    def __str__(self):\n        return self.details\n\n\ndef require_metadata_key(metadata_key):\n    check_name = \"require_metadata_key\"\n\n    def dec(fun):\n        @wraps(fun)\n        def wrapped(*args, **kwargs):\n            extension_name = args[0]\n            metadata = args[1]\n            if metadata_key not in metadata.keys():\n                raise ExtensionCheckError(extension_name, check_name, \"%s key is missing\" % metadata_key)\n            return fun(*args, **kwargs)\n        return wrapped\n    return dec\n\n\ndef parse_s4ext(ext_file_path):\n    \"\"\"Parse a Slicer extension description file.\n    :param ext_file_path: Path to a Slicer extension description file.\n    :return: Dictionary of extension metadata.\n    \"\"\"\n    ext_metadata = {}\n    with open(ext_file_path) as ext_file:\n        for line in ext_file:\n            if not line.strip() or line.startswith(\"#\"):\n                continue\n            fields = [field.strip() for field in line.split(' ', 1)]\n            assert(len(fields) <= 2)\n            ext_metadata[fields[0]] = fields[1] if len(fields) == 2 else None\n    return ext_metadata\n\n\n@require_metadata_key(\"scmurl\")\ndef check_scmurl_syntax(extension_name, metadata):\n    check_name = \"check_scmurl_syntax\"\n\n    if \"://\" not in metadata[\"scmurl\"]:\n        raise ExtensionCheckError(extension_name, check_name, \"scmurl do not match scheme://host/path\")\n\n    supported_schemes = [\"git\", \"https\", \"svn\"]\n    scheme = urlparse.urlsplit(metadata[\"scmurl\"]).scheme\n    if scheme not in supported_schemes:\n        raise ExtensionCheckError(\n            extension_name, check_name,\n            \"scmurl scheme is '%s' but it should by any of %s\" % (scheme, supported_schemes))\n\n\n@require_metadata_key(\"scmurl\")\n@require_metadata_key(\"scm\")\ndef check_git_repository_name(extension_name, metadata):\n    \"\"\"See https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ#Should_the_name_of_the_source_repository_match_the_name_of_the_extension_.3F\n    \"\"\"\n    check_name = \"check_git_repository_name\"\n\n    if metadata[\"scm\"] != \"git\":\n        return\n\n    repo_name = os.path.splitext(urlparse.urlsplit(metadata[\"scmurl\"]).path.split(\"/\")[-1])[0]\n\n    if not repo_name.startswith(\"Slicer\"):\n\n        variations = [prefix + repo_name for prefix in [\"Slicer-\", \"Slicer_\", \"SlicerExtension-\", \"SlicerExtension_\"]]\n\n        raise ExtensionCheckError(\n            extension_name, check_name,\n            textwrap.dedent(\"\"\"\n            extension repository name is '%s'. Please, consider changing it to 'Slicer%s' or any of\n            these variations %s.\n            \"\"\" % (\n                repo_name, repo_name, variations)))\n\ndef check_dependencies(directory):\n    import os\n    required_extensions = {}  # for each extension it contains a list of extensions that require it\n    available_extensions = []\n    for filename in os.listdir(directory):\n        f = os.path.join(directory, filename)\n        if not os.path.isfile(f):\n            continue\n        extension_name = os.path.splitext(os.path.basename(filename))[0]\n        available_extensions.append(extension_name)\n        extension_description = parse_s4ext(f)\n        if 'depends' not in extension_description:\n            continue\n        dependencies = extension_description['depends'].split(' ')\n        for dependency in dependencies:\n            if dependency == 'NA':\n                # special value, just a placeholder that must be ignored\n                continue\n            if dependency in required_extensions:\n                required_extensions[dependency].append(extension_name)\n            else:\n                required_extensions[dependency] = [extension_name]\n    print(f\"Checked dependency between {len(available_extensions)} extensions.\")\n    error_count = 0\n    for extension in required_extensions:\n        if extension in available_extensions:\n            # required extension is found\n            continue\n        required_by_extensions = ', '.join(required_extensions[extension])\n        print(f\"{extension} extension is not found. It is required by extension: {required_by_extensions}.\")\n        error_count += 1\n    return error_count\n\ndef main():\n    parser = argparse.ArgumentParser(\n        description='Validate extension description files.')\n    parser.add_argument(\n        \"--check-git-repository-name\", action=\"store_true\",\n        help=\"Check extension git repository name. Disabled by default.\")\n    parser.add_argument(\"-d\", \"--check-dependencies\", help=\"Check all extension dsecription files in the provided folder.\")\n    parser.add_argument(\"/path/to/description.s4ext\", nargs='*')\n    args = parser.parse_args()\n\n    checks = []\n\n    if args.check_git_repository_name:\n        checks.append(check_git_repository_name)\n\n    if not checks:\n        checks = [\n            check_scmurl_syntax,\n        ]\n\n    total_failure_count = 0\n\n    file_paths = getattr(args, \"/path/to/description.s4ext\")\n    for file_path in file_paths:\n        extension_name = os.path.splitext(os.path.basename(file_path))[0]\n\n        failures = []\n \n        metadata = parse_s4ext(file_path)\n        for check in checks:\n            try:\n                check(extension_name, metadata)\n            except ExtensionCheckError as exc:\n                failures.append(str(exc))\n\n        if failures:\n            total_failure_count += len(failures)\n            print(\"%s.s4ext\" % extension_name)\n            for failure in set(failures):\n                print(\"  %s\" % failure)\n\n    print(f\"Checked content of {len(file_paths)} description files.\")\n\n\n    if args.check_dependencies:\n        total_failure_count += check_dependencies(args.check_dependencies)\n\n    print(f\"Total errors found in extension descriptions: {total_failure_count}\")\n    sys.exit(total_failure_count)\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "scripts/check_description_files.py"}]}