Flatten flags and aliases for loaders, so cl-args override as expected. This prevents issues such as an alias pointing to InteractiveShell, but a config file setting the same trait in TerminalInteraciveShell getting inappropriate priority over the command-line arg. A
(self)
| 722 | self.subapp.initialize(argv) |
| 723 | |
| 724 | def flatten_flags(self) -> tuple[dict[str, t.Any], dict[str, t.Any]]: |
| 725 | """Flatten flags and aliases for loaders, so cl-args override as expected. |
| 726 | |
| 727 | This prevents issues such as an alias pointing to InteractiveShell, |
| 728 | but a config file setting the same trait in TerminalInteraciveShell |
| 729 | getting inappropriate priority over the command-line arg. |
| 730 | Also, loaders expect ``(key: longname)`` and not ``key: (longname, help)`` items. |
| 731 | |
| 732 | Only aliases with exactly one descendent in the class list |
| 733 | will be promoted. |
| 734 | |
| 735 | """ |
| 736 | # build a tree of classes in our list that inherit from a particular |
| 737 | # it will be a dict by parent classname of classes in our list |
| 738 | # that are descendents |
| 739 | mro_tree = defaultdict(list) |
| 740 | for cls in self.classes: |
| 741 | clsname = cls.__name__ |
| 742 | for parent in cls.mro()[1:-3]: |
| 743 | # exclude cls itself and Configurable,HasTraits,object |
| 744 | mro_tree[parent.__name__].append(clsname) |
| 745 | # flatten aliases, which have the form: |
| 746 | # { 'alias' : 'Class.trait' } |
| 747 | aliases: dict[str, str] = {} |
| 748 | for alias, longname in self.aliases.items(): |
| 749 | if isinstance(longname, tuple): |
| 750 | longname, _ = longname |
| 751 | cls, trait = longname.split(".", 1) |
| 752 | children = mro_tree[cls] # type:ignore[index] |
| 753 | if len(children) == 1: |
| 754 | # exactly one descendent, promote alias |
| 755 | cls = children[0] # type:ignore[assignment] |
| 756 | if not isinstance(aliases, tuple): # type:ignore[unreachable] |
| 757 | alias = (alias,) # type:ignore[assignment] |
| 758 | for al in alias: |
| 759 | aliases[al] = ".".join([cls, trait]) # type:ignore[list-item] |
| 760 | |
| 761 | # flatten flags, which are of the form: |
| 762 | # { 'key' : ({'Cls' : {'trait' : value}}, 'help')} |
| 763 | flags = {} |
| 764 | for key, (flagdict, help) in self.flags.items(): |
| 765 | newflag: dict[t.Any, t.Any] = {} |
| 766 | for cls, subdict in flagdict.items(): |
| 767 | children = mro_tree[cls] # type:ignore[index] |
| 768 | # exactly one descendent, promote flag section |
| 769 | if len(children) == 1: |
| 770 | cls = children[0] # type:ignore[assignment] |
| 771 | |
| 772 | if cls in newflag: |
| 773 | newflag[cls].update(subdict) |
| 774 | else: |
| 775 | newflag[cls] = subdict |
| 776 | |
| 777 | if not isinstance(key, tuple): # type:ignore[unreachable] |
| 778 | key = (key,) # type:ignore[assignment] |
| 779 | for k in key: |
| 780 | flags[k] = (newflag, help) |
| 781 | return flags, aliases |
no test coverage detected