This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Heavily refactored bundle

+333 -305
-1
oreo/oreo.py
··· 22 22 from rich import print 23 23 from thefuzz import process 24 24 from unittest import mock 25 - from rich.pretty import pprint 26 25 27 26 from .confirm import ConfirmOreo 28 27
+287 -285
packages/bundle/bundle/bundle.py
··· 22 22 import hydrox.typing as ht 23 23 from jugulis import funcdict, Hydreigon, Deino, iscallableclass 24 24 import re 25 - from functools import partial, cached_property, reduce, cache 25 + from functools import partial, cached_property, reduce 26 26 from inspect import Signature, Parameter, isclass 27 27 import collections.abc as abc 28 28 from string import ascii_lowercase as lower, ascii_uppercase as upper ··· 34 34 from .functions import reducedict, eq, rich_repr 35 35 from .types import Pass, Password 36 36 from random import choice 37 - from rich.console import Console 37 + from uuid import uuid4 38 38 39 39 # TODO: Should `__qualname__` be checked as well if it has no `.`? 40 + # TODO: In the same vein, should the `__qualname__` and `__name__` of dictionaries be used as names? 40 41 41 42 42 43 class Bundles(dict): 43 44 def __getattr__(self, attr): 44 - return self[attr] 45 + if attr in self: 46 + return self[attr] 47 + raise AttributeError() 45 48 46 49 47 50 class bundler(Bundles): 48 - def __init__(self, start, stop, *types, name="f", shared_name="g"): 51 + def __init__(self, start, stop, *types, name="f", shared_name="g", starter=None): 49 52 self.start = start 50 53 self.stop = stop 51 54 self.rstop = self.stop + 1 ··· 55 58 self.under_share = self.shared_name + "_" 56 59 self.dunder_share = self.shared_name + "__" 57 60 super().__init__() 58 - tn = get_name(self.types[0]) 59 - exec( 60 - f"@bundle\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...", 61 - locals=ChainMap(self, {"bundle": bundle}), 62 - ) 63 - exec( 64 - f"@{self.name}.up\n@bundle\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...", 65 - locals=ChainMap(self, {"bundle": bundle}), 66 - ) 67 - exec( 68 - f"@{self.name}.up\n@bundle\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...", 69 - locals=ChainMap(self, {"bundle": bundle}), 70 - ) 71 - for t in self.types[1:]: 72 - tn = get_name(t) 61 + if starter: 62 + self.update(starter) 63 + self.root = self[self.name] 64 + else: 65 + tn = get_name(self.types[0]) 73 66 exec( 74 - f"@{self.name}.up\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...", 75 - locals=self, 67 + f"@bundle\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...", 68 + locals=ChainMap(self, {"bundle": bundle}), 76 69 ) 77 70 exec( 78 - f"@{self.name}.up\n@{self.under_share}.up\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...", 71 + f"@{self.name}.up\n@bundle\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...", 79 72 locals=ChainMap(self, {"bundle": bundle}), 80 73 ) 81 74 exec( 82 - f"@{self.name}.up\n@{self.dunder_share}.up\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...", 75 + f"@{self.name}.up\n@bundle\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...", 83 76 locals=ChainMap(self, {"bundle": bundle}), 84 77 ) 85 - self.root = self[self.name] 86 - self.init(self.name) 78 + for t in self.types[1:]: 79 + tn = get_name(t) 80 + exec( 81 + f"@{self.name}.up\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...", 82 + locals=self, 83 + ) 84 + exec( 85 + f"@{self.name}.up\n@{self.under_share}.up\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...", 86 + locals=ChainMap(self, {"bundle": bundle}), 87 + ) 88 + exec( 89 + f"@{self.name}.up\n@{self.dunder_share}.up\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...", 90 + locals=ChainMap(self, {"bundle": bundle}), 91 + ) 92 + self.root = self[self.name] 93 + self.init(self.name) 87 94 88 95 def __eq__(self, other): 89 96 if isinstance(other, self.__class__): ··· 128 135 ) 129 136 130 137 @cached_property 131 - def functions(self): 138 + def deinos(self): 132 139 return Bundles( 133 140 reduce( 134 141 dict.__or__, 135 142 ( 136 143 { 137 - k + get_name(d.__signature__.return_annotation)[0]: d.__func__ 138 - for d in v.func 144 + k + get_name(d.__signature__.return_annotation)[0]: d 145 + for d in v.funcs 139 146 } 140 147 for k, v in self.items() 141 148 ), ··· 143 150 ) 144 151 145 152 @cached_property 153 + def functions(self): 154 + return Bundles({k: v.__func__ for k, v in self.deinos.items()}) 155 + 156 + @cached_property 146 157 def function_lists(self): 147 158 return Bundles( 148 159 reduce( 149 160 dict.__or__, 150 - ({k: [d.__func__ for d in v.func]} for k, v in self.items()), 161 + ({k: [d.__func__ for d in v.funcs]} for k, v in self.items()), 151 162 ) 152 163 ) 153 164 154 - @cache 155 - def type(self, *types): 156 - bundles = Bundles( 157 - { 158 - k: bundle(*[self.functions[k + get_name(t)[0]] for t in types]) 159 - for k in self 160 - } 165 + def filter_types(self, n, b, types, root): 166 + for t in types: 167 + d = self.deinos[n + get_name(t)[0]] 168 + if d in b.funcs: 169 + b.funcs.remove(d) 170 + b.func = self.deinos[n + get_name(root)[0]] 171 + for k, v in b.items(): 172 + self.filter_types(k, v, types, root) 173 + return b 174 + 175 + def copy(self): 176 + return self.__class__( 177 + self.start, 178 + self.stop, 179 + *self.types, 180 + name=self.name, 181 + shared_name=self.shared_name, 182 + starter={k: v.copy() for k, v in self.items()}, 161 183 ) 162 - bundles[self.name].up(bundles[self.under_share]) 163 - bundles[self.name].up(bundles[self.dunder_share]) 184 + 185 + def type(self, *types): 186 + bundles = self.copy() 164 187 for k, v in bundles.items(): 165 - if k.startswith(self.name) and k != self.name: 166 - bundles[k[0:-1]].up(v) 167 - v.up(bundles[k.replace(self.name, self.shared_name)[0:-1]]) 188 + self.filter_types(k, v, [t for t in self.types if t not in types], types[0]) 168 189 return bundles 169 190 170 - @cache 171 191 def cls(self, name=None): 172 192 name_was_none = name is None 173 193 bundles = Bundles() if name_was_none else {} ··· 185 205 cls = self.cls(name=n) 186 206 bundles.update(cls) 187 207 namespace[n] = cls[n] 188 - bundles[name] = type(name, bases, namespace) 208 + bundles[name] = result = type(name, bases, namespace) 189 209 if name_was_none: 190 210 under_names = (self.under_share, "__init__") 191 211 under_namespace = f"\n\t{choice(under_names)} = ".join( ··· 216 236 globals=self.functions, 217 237 locals=bundles, 218 238 ) 239 + for n in ns: 240 + result.append(bundles[n]) 219 241 return bundles 220 242 221 243 ··· 300 322 return isinmrosubclass(subclass, click.Group) or super().__subclasscheck__( 301 323 subclass 302 324 ) 325 + 326 + @staticmethod 327 + def name_is_bundled(name): 328 + return name.startswith("__bundle_") 303 329 304 330 @staticmethod 305 331 def shortform_predicate(name, arg): ··· 554 580 # TODO: Plan: 555 581 # * If the first function is a `Collection` or a dictionary and there are no more functions, 556 582 # the bundle is rootless; otherwise, flatten collections and use dictionary keys as names for their values. 583 + # * If I decide that children can be nameless, give them a "hidden" name so they aren't overidden; 584 + # remember that children can be nameless because every bundle is it's own application. 557 585 558 586 559 587 class bundle(funcdict, metaclass=Bundle, _subclass=True): ··· 568 596 569 597 if funcs and isinstance(funcs[0], str): 570 598 kwargs = {"name": funcs[0]} | click_kwargs 571 - func, *bases = funcs[1] 572 - result = func.append(funcs[2], **kwargs) 573 - for base in bases: 574 - base.append(result, **kwargs) 575 - return result 599 + return [func.append(funcs[2], **kwargs) for func in funcs[1]][0] 576 600 577 601 return super().__new__(_cls, *funcs, **click_kwargs) 578 - 579 - @property 580 - def __name__(self): 581 - return self.__click_kwargs__.get("name", self.func.__name__) 582 - 583 - @__name__.setter 584 - def __name__(self, value): 585 - self.__click_kwargs__["name"] = self.func.__name__ = value 586 602 587 603 def __call__(self, *args, **kwargs): 588 604 return self.func(*args, **kwargs) ··· 592 608 self.__class__.__name__, 593 609 self.__name__, 594 610 self.func, 611 + self.funcs, 595 612 reducedict(self.__click_kwargs__), 596 613 reducedict(self), 597 614 ) ··· 602 619 # (self.__name__ == other.__name__) 603 620 # and (self.func == other.func) 604 621 (self.func == other.func) 622 + and (self.funcs == other.funcs) 605 623 and (self.__click_kwargs__ == other.__click_kwargs__) 606 624 and super().__eq__(other) 607 625 ): ··· 616 634 ) 617 635 return NotImplemented 618 636 619 - def dunder_check(self, attr): 620 - return not attr.startswith("__") or attr in ("__init__",) 621 - 622 637 def process_click_kwargs(self, func, *click_kwargs): 623 - return Dict( 624 - {"name": getattr(func, "__name__", "")} 625 - | getattr(func, "__click_kwargs__", {}) 626 - ) | reduce(Dict.__or__, click_kwargs) 638 + click_kwargs = reduce( 639 + Dict.__or__, click_kwargs, getattr(func, "__click_kwargs__", {}) 640 + ) 641 + if not click_kwargs.get("name"): 642 + click_kwargs["name"] = getattr(func, "__name__", self.make_name()) 643 + return click_kwargs 627 644 628 - def process_func(self, func, *click_kwargs): 629 - fclick_kwargs = self.process_click_kwargs(func, *click_kwargs) 630 - fname = fclick_kwargs["name"] 631 - if not self.__name__ and fname: 632 - self.__name__ = fname 633 - return fclick_kwargs 645 + def make_name(self): 646 + return f"__bundle_{str(uuid4()).split('-')[0]}__" 634 647 635 - # TODO: Simplify and combine the various functions. 636 - def pre_process_extend(self, func=None, *funcs, **click_kwargs): 637 - fclick_kwargs_list = [] 638 - new_funcs = [] 639 - for f in (func, *funcs): 640 - if isclass(f): 641 - if funcs: 642 - for k in dir(f): 643 - if self.dunder_check(k): 644 - v = getattr(f, k) 645 - fclick_kwargs_list.append( 646 - self.process_func( 647 - v, 648 - click_kwargs, 649 - {"name": f.__name__ if k == "__init__" else k}, 650 - ) 651 - ) 652 - new_funcs.append(v) 653 - else: 654 - fclick_kwargs_list.append(self.process_func(f, click_kwargs)) 655 - new_funcs.append(f) 648 + def make_deino(self, func: abc.Callable) -> Deino: 649 + return Deino(func, **self.deino_kwargs) 650 + 651 + def get_func_name(self, func): 652 + return getattr(func, "__click_kwargs__", {}).get( 653 + "name", getattr(func, "__name__", "") 654 + ) 655 + 656 + def __init__(self, func=None, *funcs, debug=False, **click_kwargs): 657 + self.debug = debug 658 + # TODO 659 + if isinstance(func, str): 660 + self.__name__ = getattr( 661 + click_kwargs, 662 + "pop" if funcs or not getattr(func, "__name__", "") else "get", 663 + )("name", func) 664 + 665 + else: 666 + super().__init__() 667 + self.deino_kwargs = { 668 + "default_va_annotation": typing.Any, 669 + "default_vk_annotation": typing.Any, 670 + } 671 + self.func = None 672 + self.funcs = Hydreigon(**self.deino_kwargs) 673 + if "name" in click_kwargs: 674 + self.__name__ = getattr( 675 + click_kwargs, 676 + "pop" if funcs else "get", 677 + )("name") 656 678 else: 657 - match f: 658 - case bundle(): 659 - fclick_kwargs_list.append(self.process_func(f, click_kwargs)) 660 - new_funcs.append(f) 661 - case dict(): 662 - if funcs: 663 - for k, v in f.items(): 664 - if self.dunder_check(k): 665 - fclick_kwargs_list.append( 666 - self.process_func(v, click_kwargs, {"name": k}) 667 - ) 668 - new_funcs.append(v) 669 - else: 670 - fclick_kwargs_list.append( 671 - self.process_func(f, click_kwargs) 672 - ) 673 - new_funcs.append(f) 674 - case Hydreigon(): 675 - ... 676 - case Collection(): 677 - if funcs: 678 - for item in f: 679 - fclick_kwargs_list.append( 680 - self.process_func(item, click_kwargs) 681 - ) 682 - new_funcs.append(item) 683 - else: 684 - fclick_kwargs_list.append( 685 - self.process_func(f, click_kwargs) 686 - ) 687 - new_funcs.append(f) 688 - case _: 689 - fclick_kwargs_list.append(self.process_func(f, click_kwargs)) 690 - new_funcs.append(f) 691 - func, *funcs = new_funcs 692 - result = self.append(func, processed_click_kwargs=fclick_kwargs_list[0]) 693 - for f, kwargs in zip(funcs, fclick_kwargs_list[1:]): 694 - result.append(f, processed_click_kwargs=kwargs) 695 - return result 679 + for f in (func, *funcs): 680 + if fname := self.get_func_name(f): 681 + self.__name__ = fname 682 + break 683 + else: 684 + self.__name__ = self.make_name() 685 + self.funcs.__name__ = self.__name__ 686 + self.__click_kwargs__ = Dict() 687 + self.append(func, *funcs, **click_kwargs) 696 688 697 689 def up(self, *funcs, **click_kwargs): 698 690 if isinstance(self, bundle): 699 691 if as_decorator(query=query): 700 692 701 693 def wrapper(func): 702 - return self.pre_process_extend(func, *funcs, **click_kwargs) 694 + return self.append(func, *funcs, **click_kwargs) 703 695 704 696 return wrapper 705 - 706 - return self.pre_process_extend(*funcs, **click_kwargs) 697 + return self.append(*funcs, **click_kwargs) 707 698 return Bundle.up(self, *funcs, **click_kwargs) 708 699 709 - extend = up 710 - roar = up 700 + def dunder_check(self, attr): 701 + return not attr.startswith("__") or attr in ("__init__",) 711 702 712 - def __init__(self, func=None, *funcs, **click_kwargs): 713 - if not isinstance(func, str): 714 - super().__init__() 715 - self.func = Hydreigon( 716 - default_va_annotation=typing.Any, default_vk_annotation=typing.Any 717 - ) 718 - self.__click_kwargs__ = Dict(click_kwargs) 719 - if funcs: 720 - click_kwargs.pop("name", None) 721 - self.up(func, *funcs, **click_kwargs) 703 + def init_swap(self, attr, name=None): 704 + name = self.__name__ if name is None else name 705 + return name if attr == "__init__" else attr 722 706 723 - def process_append(self, func, fname, child): 724 - if child: 725 - if fname in self: 726 - result = self[fname] 727 - exists = True 728 - else: 729 - result = self 730 - exists = False 731 - else: 732 - result = self 733 - exists = True 734 - if isclass(func): 735 - if not exists: 736 - self[fname] = result = bundle(name=fname) 737 - for name in dir(func): 738 - if self.dunder_check(name): 739 - result.append( 740 - getattr(func, name), name=fname if name == "__init__" else name 741 - ) 707 + def append(self, func=None, *funcs, **click_kwargs): 708 + if funcs: 709 + for f in (func, *funcs): 710 + self.append(f) 711 + return self 742 712 else: 743 - match func: 744 - case dict(): 745 - if not exists: 746 - self[fname] = result = bundle(name=fname) 747 - for name, attr in func.items(): 748 - if self.dunder_check(name): 749 - result.append(attr, name=name) 750 - case Hydreigon(): 751 - if exists: 752 - result.func.extend(func) 713 + click_kwargs = self.process_click_kwargs(func, click_kwargs) 714 + name = click_kwargs.name 715 + if name in (self.__name__, "__init__"): 716 + self.__click_kwargs__ |= click_kwargs 717 + if func is not None: 718 + if isclass(func): 719 + for k in dir(func): 720 + if self.dunder_check(k): 721 + self.append( 722 + getattr(func, k), name=self.init_swap(k, name) 723 + ) 753 724 else: 754 - self[fname] = result = bundle(name=fname) 755 - result.func = func 725 + match func: 726 + case bundle(): 727 + self |= func 728 + case dict(): 729 + for k, v in func.items(): 730 + if self.dunder_check(k): 731 + self.append(v, name=self.init_swap(k, name)) 732 + case Hydreigon(): 733 + self.funcs += func 734 + case Collection(): 735 + for item in func: 736 + self.append(item) 737 + case _: 738 + self.funcs.append(func) 739 + if not self.func: 740 + # NOTE: This needs to be created separately if I want 741 + # the function arguments to be type checked. 742 + self.func = self.make_deino(func) 743 + return self 756 744 757 - # TODO 758 - # case ht.Coll(): 759 - # case abc.Iterable(): 760 - case Collection(): 761 - if not exists: 762 - self[fname] = result = bundle(name=fname) 763 - for f in func: 764 - if isclass(f): 765 - for name in dir(f): 766 - if self.dunder_check(name): 767 - result.append( 768 - getattr(f, name), 769 - name=f.__name__ if name == "__init__" else name, 770 - ) 771 - else: 772 - match f: 773 - case bundle(): 774 - result.append(f) 775 - case dict(): 776 - for name, attr in f.items(): 777 - if self.dunder_check(name): 778 - result.append(attr, name=name) 779 - # case Hydreigon(): 780 - # ... 781 - # case Collection(): 782 - # ... 783 - case _: 784 - result.append(f) 745 + # TODO: How do I deal with names and kwargs? 746 + elif isinstance(func, bundle): 747 + self[name] = func.copy() 785 748 786 - case _: 787 - if exists: 788 - result.func.append(func) 749 + elif self.__class__.name_is_bundled(name): 750 + if func is not None: 751 + if isclass(func): 752 + for k in dir(func): 753 + if self.dunder_check(k): 754 + v = getattr(func, k) 755 + k = self.init_swap(k, name) 756 + if k in self: 757 + self[k].append(v, name=k) 758 + else: 759 + self[k] = bundle(v, name=k) 789 760 else: 790 - self[fname] = result = bundle(func, name=fname) 791 - 792 - return result 793 - 794 - def append(self, func=None, /, processed_click_kwargs=None, **click_kwargs): 795 - click_kwargs = ( 796 - self.process_click_kwargs(func, click_kwargs) 797 - if processed_click_kwargs is None 798 - else processed_click_kwargs 799 - ) 800 - if not (fname := click_kwargs.get("name")): 801 - click_kwargs["name"] = fname = getattr(func, "__name__", "") 802 - if fname in (self.__name__, "__init__"): 803 - self.__click_kwargs__ |= click_kwargs 804 - if func is not None: 805 - if not isinstance(func, bundle): 806 - return self.process_append(func, fname, False) 807 - 808 - # NOTE: At any given moment, there can be only one instance of `self`, 809 - # i.e., only one version of this command. 810 - # TODO: Not necessarily, as the result can be assigned to a variable with another name. 811 - # Therefore, find a way to update the old version of func as well. 812 - # TODO: ... Wouldn't `func` be updated anyway, as `self = func`? 813 - self |= func 814 - 815 - return self 816 - 817 - if fname: 818 - if isinstance(func, bundle): 819 - # NOTE: At any given moment, there can be only one instance of `fname`, 820 - # i.e., only one version of this command. 821 - # TODO: Not necessarily, as the result can be assigned to a variable with another name. 822 - # Therefore, find a way to update the old version of func as well. 823 - # TODO: ... Wouldn't `func` be updated anyway `if fname in self`, as `self[fname] = func`? 824 - if fname in self: 825 - self[fname] |= func 761 + match func: 762 + case dict(): 763 + for k, v in func.items(): 764 + if self.dunder_check(k): 765 + k = self.init_swap(k, name) 766 + if k in self: 767 + self[k].append(v, name=k) 768 + else: 769 + self[k] = bundle(v, name=k) 770 + case Hydreigon(): 771 + self.funcs += func 772 + case Collection(): 773 + for item in func: 774 + self.append(item) 775 + case _: 776 + self.funcs.append(func) 777 + if not self.func: 778 + # NOTE: This needs to be created separately if I want 779 + # the function arguments to be type checked. 780 + self.func = self.make_deino(func) 781 + return self 782 + elif func is None: 783 + if name in self: 784 + self[name].__click_kwargs__ |= click_kwargs 826 785 else: 827 - self[fname] = func 828 - return self[fname] 829 - 830 - if func is None: 831 - if fname in self: 832 - return self[fname] 833 - self[fname] = result = bundle(**click_kwargs) 834 - return result 835 - return self.process_append(func, fname, True) 786 + self[name] = bundle(**click_kwargs) 787 + elif isclass(func): 788 + if name in self: 789 + result = self[name] 790 + result.__click_kwargs__ |= click_kwargs 791 + else: 792 + self[name] = result = bundle(**click_kwargs) 793 + for k in dir(func): 794 + if self.dunder_check(k): 795 + result.append(getattr(func, k), name=self.init_swap(k, name)) 796 + else: 797 + match func: 798 + case dict(): 799 + if name in self: 800 + result = self[name] 801 + result.__click_kwargs__ |= click_kwargs 802 + else: 803 + self[name] = result = bundle(**click_kwargs) 804 + for k, v in func.items(): 805 + if self.dunder_check(k): 806 + result.append(v, name=self.init_swap(k, name)) 807 + case Hydreigon(): 808 + if name in self: 809 + self[name].funcs += func 810 + self[name].__click_kwargs__ |= click_kwargs 811 + else: 812 + self[name] = bundle(func, **click_kwargs) 813 + case Collection(): 814 + if name in self: 815 + result = self[name] 816 + result.__click_kwargs__ |= click_kwargs 817 + else: 818 + self[name] = result = bundle(**click_kwargs) 819 + for item in func: 820 + result.append(func) 821 + case _: 822 + if name in self: 823 + self[name].append(func, **click_kwargs) 824 + else: 825 + self[name] = bundle(func, **click_kwargs) 826 + return self[name] 836 827 837 828 def __rich_repr__(self): 838 - yield self.__name__ 839 - yield self.func 840 - yield dict(self) 829 + yield getattr( 830 + self.func, 831 + "__name__", 832 + "main" if self.__class__.name_is_bundled(self.__name__) else self.__name__, 833 + ) 834 + yield "command", self.__name__ 835 + yield "root", self.func 836 + yield "functions", self.funcs 837 + yield "subcommands", dict(self) 841 838 842 839 def update(self, other): 843 840 if isinstance(other, self.__class__): 844 - self.func += other.func 841 + other = other.copy() 842 + self.func = other.func 843 + self.funcs += other.funcs 845 844 self.__click_kwargs__ |= other.__click_kwargs__ 846 845 # TODO: Should the values of other be converted to bundles, 847 846 # like in `funcdict`? 848 847 return super().update(other) 849 848 850 - # TODO: This will make the result a rootless application. 851 - # Do I want that? 852 849 def copy(self): 853 - result = self.__class__(self) 854 - result.func = self.func.copy() 850 + result = self.__class__(**self.__click_kwargs__) 851 + for k, v in self.items(): 852 + result[k] = v.copy() 853 + result.func = self.func.copy() if self.func else None 854 + result.funcs = self.funcs.copy() 855 855 return result 856 856 857 857 def __ror__(self, other): ··· 877 877 return args 878 878 879 879 # TODO: Simplify. 880 - def compile(self, parent=click, *, click_kwargs=None, only_params=True): 881 - hydreigon: Hydreigon 882 - deino: Deino 883 - func: abc.Callable 884 - if self.func: 885 - hydreigon = self.func 886 - else: 887 - hydreigon = Hydreigon(lambda: None) 888 - deino: Deino = hydreigon[0] 889 - func = deino.__func__ 880 + def compile(self, parent=click, *, name=None, click_kwargs=None, only_params=True): 881 + if name is None: 882 + name = ( 883 + "main" 884 + if self.__class__.name_is_bundled(self.__name__) 885 + else self.__name__ 886 + ) 887 + deino: Deino = self.func or self.make_deino(lambda: None) 888 + func: abc.Callable = deino.__func__ 890 889 bundled_args = defaultdict( 891 890 list, 892 - getattr(hydreigon, "__bundled_args__", {}) 893 - | getattr(deino, "__bundled_args__", {}) 891 + getattr(deino, "__bundled_args__", {}) 894 892 | getattr(func, "__bundled_args__", {}), 895 893 ) 896 894 bundled_kwargs = Dict( 897 - getattr(hydreigon, "__bundled_kwargs__", {}) 898 - | getattr(deino, "__bundled_kwargs__", {}) 895 + getattr(deino, "__bundled_kwargs__", {}) 899 896 | getattr(func, "__bundled_kwargs__", {}) 900 897 ) 901 898 docstring: Docstring = deino.__docstring__ ··· 922 919 func.__click_params__ = click_params = [ 923 920 click_param 924 921 for click_param in flatten( 925 - getattr(hydreigon, "__click_params__", tuple()), 926 922 getattr(deino, "__click_params__", tuple()), 927 923 getattr(func, "__click_params__", tuple()), 928 924 ) 929 925 if click_param.name not in disabled 930 926 ] 931 927 932 - for name in param_keys - {param.name for param in click_params}: 933 - param: Parameter = params[name] 928 + for param_name in param_keys - {param.name for param in click_params}: 929 + param: Parameter = params[param_name] 934 930 annotation = param.annotation 935 931 if annotation is Pass: 936 932 func = click.pass_context(func) ··· 945 941 else: 946 942 kind = param.kind 947 943 func = getattr(click, self.__class__.process_clicker(kind))( 948 - *self.process_names(name, kind, bundled_args[name], click_params), 944 + *self.process_names( 945 + param_name, kind, bundled_args[param_name], click_params 946 + ), 949 947 **self.__class__.process_kwargs( 950 - name, param, bundled_kwargs[name], docstring_params[name] 948 + param_name, 949 + param, 950 + bundled_kwargs[param_name], 951 + docstring_params[param_name], 951 952 ), 952 953 )(func) 953 954 ··· 976 977 if isinstance(parent, click.Command) 977 978 else bundle.defaults["group"] 978 979 ) 979 - | {"name": self.__name__} 980 980 | dockwargs 981 981 | self.__click_kwargs__ 982 + | {"name": name} 982 983 ) 983 984 if "cls" in click_kwargs: 984 985 if not hasattr(cls := click_kwargs["cls"], "__rich_repr__"): 985 986 cls.__rich_repr__ = partial(rich_repr, only_params=only_params) 986 987 group = parent.group(**click_kwargs)(normalize.function(func, exclude=disabled)) 987 - for v in self.values(): 988 - v.compile(group, click_kwargs=click_kwargs) 988 + for k, v in self.items(): 989 + if not self.__class__.name_is_bundled(k): 990 + v.compile(group, name=k, click_kwargs=click_kwargs) 989 991 return group 990 992 991 993 def flip(self, *args, **kwargs): 992 994 return self.compile()(*args, **kwargs) 993 995 994 996 def invoke(self, *args, **kwargs): 995 - self.func.raise_if_empty() 996 - return self.func.invoke(*args, **kwargs) 997 + self.funcs.raise_if_empty() 998 + return self.funcs.invoke(*args, **kwargs) 997 999 998 1000 def run(self, *args, runner=None, attr="return_value", **kwargs): 999 1001 kwargs = {"standalone_mode": False, "catch_exceptions": False} | kwargs ··· 1004 1006 1005 1007 @property 1006 1008 def root(self): 1007 - self.func.raise_if_empty() 1008 - return self.func[0] 1009 + self.funcs.raise_if_empty() 1010 + return self.func 1009 1011 1010 1012 def document(self, docstring, *args, **kwargs): 1011 1013 if args or kwargs:
+20 -15
packages/bundle/bundle/tests/test_bundle.py
··· 302 302 pprint(b3) 303 303 304 304 names = (b1.__name__, b2.__name__, b3.__name__) 305 - assert not any(names) 305 + assert all(map(bundle.name_is_bundled, names)) 306 306 assert integers.f.__name__ not in names 307 307 308 - funcs = (b1.func, b2.func, b3.func) 308 + funcs = (b1.funcs, b2.funcs, b3.funcs) 309 309 assert not any(funcs) 310 - assert integers.f.func not in funcs 310 + assert integers.f.funcs not in funcs 311 311 312 312 assert b1 == b2 == b3 313 313 assert integers.g_ == b1.g_ == b2.g_ == b3.g_ ··· 435 435 assert strings.f1 == b1f1 == b2f1 436 436 437 437 def test_root_inherited_child_decorated_class(self, bundles, strings, functions): 438 + pprint(bundles.f1) 439 + pprint(strings.f1) 440 + 438 441 class f1(bundle): 439 442 __init__ = functions.f1i 440 443 __init__ = functions.f1s ··· 451 454 452 455 pprint(f1) 453 456 454 - assert bundles.f1.func == f1.func 455 - assert strings.f1.func != f1.func 456 - assert bundles.f11.func != f1.f11.func 457 - assert bundles.f12.func != f1.f12.func 458 - assert strings.f11.func == f1.f11.func 459 - assert strings.f12.func == f1.f12.func 457 + assert bundles.f1.funcs == f1.funcs 458 + assert strings.f1.funcs != f1.funcs 459 + assert bundles.f11.funcs != f1.f11.funcs 460 + assert bundles.f12.funcs != f1.f12.funcs 461 + assert strings.f11.funcs == f1.f11.funcs 462 + assert strings.f12.funcs == f1.f12.funcs 460 463 461 464 def test_root_decorated_child_inherited_class(self, bundles, strings, functions): 465 + pprint(bundles.f1) 466 + 462 467 @bundle 463 468 class f1: 464 469 __init__ = functions.f1i ··· 474 479 475 480 pprint(f1) 476 481 477 - assert bundles.f1.func != f1.func 478 - assert strings.f1.func == f1.func 479 - assert bundles.f11.func == f1.f11.func 480 - assert bundles.f12.func == f1.f12.func 481 - assert strings.f11.func != f1.f11.func 482 - assert strings.f12.func != f1.f12.func 482 + assert bundles.f1.funcs != f1.funcs 483 + assert strings.f1.funcs == f1.funcs 484 + assert bundles.f11.funcs == f1.f11.funcs 485 + assert bundles.f12.funcs == f1.f12.funcs 486 + assert strings.f11.funcs != f1.f11.funcs 487 + assert strings.f12.funcs != f1.f12.funcs 483 488 484 489 def test_shared_children(self, bundles, functions): 485 490 f11 = bundle(functions.f11i, functions.f11s)
+9
packages/bundle/test1.py
··· 1 + from bundle import bundler 2 + 3 + bundles = bundler(1, 2) 4 + functions = bundles.functions 5 + deinos = bundles.deinos 6 + integers = bundles.type(int) 7 + strings = bundles.type(str) 8 + 9 + assert hash(bundles) == hash(bundles.copy())
+1 -1
packages/jugulis/jugulis/__init__.py
··· 1 1 from .deino import Deino, format_message 2 2 from .hydreigon import Hydreigon, AmbiguityError, AvailabilityError 3 - from .jugulis import funcdict, Jugulis, jugulis, IronJugulis, IronJugudict 3 + from .jugulis import funcdict, Jugulis, jugulis, IronJugulis, IronJugudict, console 4 4 from .functions import * 5 5 from rich.traceback import install 6 6
+15 -2
packages/jugulis/jugulis/deino.py
··· 35 35 36 36 37 37 # TODO: What happens if you initialize with a Deino? 38 + # TODO: How do I copy Deinos? 38 39 class Deino: 39 40 def __init__( 40 41 self, ··· 88 89 for k, v in old_settings.items(): 89 90 setattr(self, k, v) 90 91 92 + def copy(self): 93 + return self.__class__( 94 + self.__func__, 95 + cache=self.__cache__, 96 + evolved=self.__evolved__, 97 + default_annotation=self.__default_annotation__, 98 + default_va_annotation=self.__default_va_annotation__, 99 + default_vk_annotation=self.__default_vk_annotation__, 100 + precedence=self.__precedence__, 101 + hashed=self.__hashed__, 102 + cls=self.__cls__, 103 + ) 104 + 91 105 def __eq__(self, other: Deino): 92 106 return ( 93 107 isinstance(other, self.__class__) 94 108 and (self.__func__ == other.__func__) 95 - and (self.__evolved__ == other.__evolved__) 96 109 and (self.__default_annotation__ == other.__default_annotation__) 97 110 and (self.__default_va_annotation__ == other.__default_va_annotation__) 98 111 and (self.__default_vk_annotation__ == other.__default_vk_annotation__) ··· 103 116 104 117 def __hash__(self): 105 118 return ht.reducehash( 119 + self.__class__.__name__, 106 120 self.__func__, 107 - self.__evolved__, 108 121 self.__default_annotation__, 109 122 self.__default_va_annotation__, 110 123 self.__default_vk_annotation__,
+1 -1
packages/jugulis/jugulis/hydreigon.py
··· 182 182 def copy(self): 183 183 result = self.ecopy() 184 184 result.__name__ = self.__name__ 185 - super(self.__class__, result).extend(self) 185 + super(self.__class__, result).extend(d.copy() for d in self) 186 186 return result 187 187 188 188 def ecopy(self):