Download lib/python3.12/site-packages/hydra/plugins/completion_plugin.py from parallel-reasoner/env-full: direct link, hf CLI and curl.
- Browser
- Download file 11.3 kB
-
https://huggingface.co/parallel-reasoner/env-full/resolve/ef9f3b242ae7e3f7f6941c7127ec00ad092d910e/lib/python3.12/site-packages/hydra/plugins/completion_plugin.py
- Command line
-
hf download hf://parallel-reasoner/env-full@ef9f3b242ae7e3f7f6941c7127ec00ad092d910e/lib/python3.12/site-packages/hydra/plugins/completion_plugin.py
-
curl -L -o completion_plugin.py https://huggingface.co/parallel-reasoner/env-full/resolve/ef9f3b242ae7e3f7f6941c7127ec00ad092d910e/lib/python3.12/site-packages/hydra/plugins/completion_plugin.py
11.3 kB
| # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved | |
| # TODO: Test with /miniconda3/envs/hydra36/bin/python , seems to be running python for some reason. | |
| # TODO: Add tests for completion with +prefix (should suggest config groups that are not listed) | |
| # TODO: Test completion when defaults has a missing mandatory item | |
| import os | |
| import re | |
| import sys | |
| from abc import abstractmethod | |
| from hydra.errors import ConfigCompositionException | |
| from omegaconf import ( | |
| Container, | |
| DictConfig, | |
| MissingMandatoryValue, | |
| OmegaConf, | |
| ListConfig, | |
| ) | |
| from typing import Any, List, Optional, Tuple | |
| from hydra.core.config_loader import ConfigLoader | |
| from hydra.core.object_type import ObjectType | |
| from hydra.plugins.plugin import Plugin | |
| from hydra.types import RunMode | |
| class CompletionPlugin(Plugin): | |
| def __init__(self, config_loader: ConfigLoader) -> None: | |
| self.config_loader = config_loader | |
| def install(self) -> None: | |
| ... | |
| def uninstall(self) -> None: | |
| ... | |
| def provides() -> str: | |
| """ | |
| :return: the name of the shell this plugin provides completion for | |
| """ | |
| ... | |
| def query(self, config_name: Optional[str]) -> None: | |
| ... | |
| def help(command: str) -> str: | |
| """ | |
| :param command: "install" or "uninstall" | |
| :return: command the user can run to install or uninstall this shell completion on the appropriate shell | |
| """ | |
| ... | |
| def _get_filename(filename: str) -> Tuple[Optional[str], Optional[str]]: | |
| last = filename.rfind("=") | |
| if last != -1: | |
| key_eq = filename[0 : last + 1] | |
| filename = filename[last + 1 :] | |
| prefixes = [".", "/", "\\", "./", ".\\"] | |
| if sys.platform.startswith("win"): | |
| for drive in range(ord("a"), ord("z")): | |
| prefixes.append(f"{chr(drive)}:") | |
| if not filename: | |
| return None, None | |
| for prefix in prefixes: | |
| if filename.lower().startswith(prefix): | |
| return key_eq, filename | |
| return None, None | |
| def complete_files(word: str) -> List[str]: | |
| if os.path.isdir(word): | |
| dirname = word | |
| files = os.listdir(word) | |
| file_prefix = "" | |
| else: | |
| dirname = os.path.dirname(word) | |
| if os.path.isdir(dirname): | |
| files = os.listdir(dirname) | |
| else: | |
| files = [] | |
| file_prefix = os.path.basename(word) | |
| ret = [] | |
| for file in files: | |
| if file.startswith(file_prefix): | |
| ret.append(os.path.join(dirname, file)) | |
| return ret | |
| def _get_matches(config: Container, word: str) -> List[str]: | |
| def str_rep(in_key: Any, in_value: Any) -> str: | |
| if OmegaConf.is_config(in_value): | |
| return f"{in_key}." | |
| else: | |
| return f"{in_key}=" | |
| if config is None: | |
| return [] | |
| elif OmegaConf.is_config(config): | |
| matches = [] | |
| if word.endswith(".") or word.endswith("="): | |
| exact_key = word[0:-1] | |
| try: | |
| conf_node = OmegaConf.select( | |
| config, exact_key, throw_on_missing=True | |
| ) | |
| except MissingMandatoryValue: | |
| conf_node = "" | |
| if conf_node is not None: | |
| if OmegaConf.is_config(conf_node): | |
| key_matches = CompletionPlugin._get_matches(conf_node, "") | |
| else: | |
| # primitive | |
| if isinstance(conf_node, bool): | |
| conf_node = str(conf_node).lower() | |
| key_matches = [conf_node] | |
| else: | |
| key_matches = [] | |
| matches.extend([f"{word}{match}" for match in key_matches]) | |
| else: | |
| last_dot = word.rfind(".") | |
| if last_dot != -1: | |
| base_key = word[0:last_dot] | |
| partial_key = word[last_dot + 1 :] | |
| conf_node = OmegaConf.select(config, base_key) | |
| key_matches = CompletionPlugin._get_matches(conf_node, partial_key) | |
| matches.extend([f"{base_key}.{match}" for match in key_matches]) | |
| else: | |
| if isinstance(config, DictConfig): | |
| for key, value in config.items_ex(resolve=False): | |
| str_key = str(key) | |
| if str_key.startswith(word): | |
| matches.append(str_rep(key, value)) | |
| elif OmegaConf.is_list(config): | |
| assert isinstance(config, ListConfig) | |
| for idx in range(len(config)): | |
| try: | |
| value = config[idx] | |
| if str(idx).startswith(word): | |
| matches.append(str_rep(idx, value)) | |
| except MissingMandatoryValue: | |
| matches.append(str_rep(idx, "")) | |
| else: | |
| assert False, f"Object is not an instance of config : {type(config)}" | |
| return matches | |
| def _query_config_groups( | |
| self, word: str, config_name: Optional[str], words: List[str] | |
| ) -> Tuple[List[str], bool]: | |
| is_addition = word.startswith("+") | |
| is_deletion = word.startswith("~") | |
| if is_addition or is_deletion: | |
| prefix, word = word[0], word[1:] | |
| else: | |
| prefix = "" | |
| last_eq_index = word.rfind("=") | |
| last_slash_index = word.rfind("/") | |
| exact_match: bool = False | |
| if last_eq_index != -1: | |
| parent_group = word[0:last_eq_index] | |
| results_filter = ObjectType.CONFIG | |
| else: | |
| results_filter = ObjectType.GROUP | |
| if last_slash_index == -1: | |
| parent_group = "" | |
| else: | |
| parent_group = word[0:last_slash_index] | |
| all_matched_groups = self.config_loader.get_group_options( | |
| group_name=parent_group, | |
| results_filter=results_filter, | |
| config_name=config_name, | |
| overrides=words, | |
| ) | |
| matched_groups: List[str] = [] | |
| if results_filter == ObjectType.CONFIG: | |
| for match in all_matched_groups: | |
| name = f"{parent_group}={match}" if parent_group != "" else match | |
| if name.startswith(word): | |
| matched_groups.append(name) | |
| exact_match = True | |
| elif results_filter == ObjectType.GROUP: | |
| for match in all_matched_groups: | |
| name = f"{parent_group}/{match}" if parent_group != "" else match | |
| if name.startswith(word): | |
| files = self.config_loader.get_group_options( | |
| group_name=name, | |
| results_filter=ObjectType.CONFIG, | |
| config_name=config_name, | |
| overrides=words, | |
| ) | |
| dirs = self.config_loader.get_group_options( | |
| group_name=name, | |
| results_filter=ObjectType.GROUP, | |
| config_name=config_name, | |
| overrides=words, | |
| ) | |
| if len(dirs) == 0 and len(files) > 0 and not is_deletion: | |
| name = name + "=" | |
| elif len(dirs) > 0 and len(files) == 0: | |
| name = name + "/" | |
| matched_groups.append(name) | |
| matched_groups = [f"{prefix}{group}" for group in matched_groups] | |
| return matched_groups, exact_match | |
| def _query(self, config_name: Optional[str], line: str) -> List[str]: | |
| from .._internal.utils import get_args | |
| new_word = len(line) == 0 or line[-1] == " " | |
| parsed_args = get_args(line.split()) | |
| words = parsed_args.overrides | |
| if new_word or len(words) == 0: | |
| word = "" | |
| else: | |
| word = words[-1] | |
| words = words[0:-1] | |
| fname_prefix, filename = CompletionPlugin._get_filename(word) | |
| if filename is not None: | |
| assert fname_prefix is not None | |
| result = CompletionPlugin.complete_files(filename) | |
| result = [fname_prefix + file for file in result] | |
| else: | |
| matched_groups, exact_match = self._query_config_groups( | |
| word, config_name=config_name, words=words | |
| ) | |
| config_matches: List[str] = [] | |
| if not exact_match: | |
| run_mode = RunMode.MULTIRUN if parsed_args.multirun else RunMode.RUN | |
| config_matches = [] | |
| try: | |
| config = self.config_loader.load_configuration( | |
| config_name=config_name, overrides=words, run_mode=run_mode | |
| ) | |
| config_matches = CompletionPlugin._get_matches(config, word) | |
| except ConfigCompositionException: | |
| # if config fails to load for whatever reason, do not provide config matches. | |
| # possible reasons: | |
| # - missing entry in defaults list (- group: ???) and not populated in command line | |
| # - a config file is not found | |
| # etc. | |
| pass | |
| result = list(set(matched_groups + config_matches)) | |
| return sorted(result) | |
| def strip_python_or_app_name(line: str) -> str: | |
| """ | |
| Take the command line received from shell completion, and strip the app name from it | |
| which could be at the form of python script.py or some_app. | |
| it also corrects the key (COMP_INDEX) to reflect the same location in the striped command line. | |
| :param line: input line, may contain python file.py followed=by_args.. | |
| :return: tuple(args line, key of cursor in args line) | |
| """ | |
| python_args = r"^\s*[\w\/]*python[3]?\s*[\w/\.]*\s*(.*)" | |
| app_args = r"^\s*[\w_\-=\./]+\s*(.*)" | |
| match = re.match(python_args, line) | |
| if match: | |
| return match.group(1) | |
| else: | |
| match = re.match(app_args, line) | |
| if match: | |
| return match.group(1) | |
| else: | |
| raise RuntimeError(f"Error parsing line '{line}'") | |
| class DefaultCompletionPlugin(CompletionPlugin): | |
| """ | |
| A concrete instance of CompletionPlugin that is used for testing. | |
| """ | |
| def install(self) -> None: | |
| raise NotImplementedError | |
| def uninstall(self) -> None: | |
| raise NotImplementedError | |
| def provides() -> str: | |
| raise NotImplementedError | |
| def query(self, config_name: Optional[str]) -> None: | |
| raise NotImplementedError | |
| def help(command: str) -> str: | |
| raise NotImplementedError | |