]> jfr.im git - yt-dlp.git/blobdiff - devscripts/install_deps.py
[misc] Add `hatch`, `ruff`, `pre-commit` and improve dev docs (#7409)
[yt-dlp.git] / devscripts / install_deps.py
index 715e5b044049c6d5e75f9f62ab14970dd7a3ed24..d292505458b7b95e80c846ac0714073a6f3b5179 100755 (executable)
@@ -10,6 +10,8 @@
 import re
 import subprocess
 
+from pathlib import Path
+
 from devscripts.tomlparse import parse_toml
 from devscripts.utils import read_file
 
 def parse_args():
     parser = argparse.ArgumentParser(description='Install dependencies for yt-dlp')
     parser.add_argument(
-        'input', nargs='?', metavar='TOMLFILE', default='pyproject.toml', help='Input file (default: %(default)s)')
+        'input', nargs='?', metavar='TOMLFILE', default=Path(__file__).parent.parent / 'pyproject.toml',
+        help='input file (default: %(default)s)')
     parser.add_argument(
-        '-e', '--exclude', metavar='REQUIREMENT', action='append', help='Exclude a required dependency')
+        '-e', '--exclude', metavar='DEPENDENCY', action='append',
+        help='exclude a dependency')
     parser.add_argument(
-        '-i', '--include', metavar='GROUP', action='append', help='Include an optional dependency group')
+        '-i', '--include', metavar='GROUP', action='append',
+        help='include an optional dependency group')
     parser.add_argument(
-        '-o', '--only-optional', action='store_true', help='Only install optional dependencies')
+        '-o', '--only-optional', action='store_true',
+        help='only install optional dependencies')
     parser.add_argument(
-        '-p', '--print', action='store_true', help='Only print a requirements.txt to stdout')
+        '-p', '--print', action='store_true',
+        help='only print requirements to stdout')
     parser.add_argument(
-        '-u', '--user', action='store_true', help='Install with pip as --user')
+        '-u', '--user', action='store_true',
+        help='install with pip as --user')
     return parser.parse_args()
 
 
 def main():
     args = parse_args()
-    toml_data = parse_toml(read_file(args.input))
-    deps = toml_data['project']['dependencies']
-    targets = deps.copy() if not args.only_optional else []
-
-    for exclude in args.exclude or []:
-        for dep in deps:
-            simplified_dep = re.match(r'[\w-]+', dep)[0]
-            if dep in targets and (exclude.lower() == simplified_dep.lower() or exclude == dep):
-                targets.remove(dep)
-
-    optional_deps = toml_data['project']['optional-dependencies']
-    for include in args.include or []:
-        group = optional_deps.get(include)
-        if group:
-            targets.extend(group)
+    project_table = parse_toml(read_file(args.input))['project']
+    recursive_pattern = re.compile(rf'{project_table["name"]}\[(?P<group_name>[\w-]+)\]')
+    optional_groups = project_table['optional-dependencies']
+    excludes = args.exclude or []
+
+    def yield_deps(group):
+        for dep in group:
+            if mobj := recursive_pattern.fullmatch(dep):
+                yield from optional_groups.get(mobj.group('group_name'), [])
+            else:
+                yield dep
+
+    targets = []
+    if not args.only_optional:  # `-o` should exclude 'dependencies' and the 'default' group
+        targets.extend(project_table['dependencies'])
+        if 'default' not in excludes:  # `--exclude default` should exclude entire 'default' group
+            targets.extend(yield_deps(optional_groups['default']))
+
+    for include in filter(None, map(optional_groups.get, args.include or [])):
+        targets.extend(yield_deps(include))
+
+    targets = [t for t in targets if re.match(r'[\w-]+', t).group(0).lower() not in excludes]
 
     if args.print:
         for target in targets: