alpha
Login
or
Join now
syvl.org
/
oreo
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
Heavily refactored bundle
author
syvlorg
date
1 year ago
(Jun 17, 2025, 12:56 AM -0400)
commit
8a856e65
8a856e65944814a8af8ecda2735675a39be8964a
parent
3ec2c8a8
3ec2c8a8591f4d58fea7a47118d1f0209074af5a
+333
-305
7 changed files
Expand all
Collapse all
Unified
Split
oreo
oreo.py
packages
bundle
bundle
bundle.py
tests
test_bundle.py
test1.py
jugulis
jugulis
__init__.py
deino.py
hydreigon.py
-1
oreo/oreo.py
Reviewed
···
22
22
from rich import print
23
23
from thefuzz import process
24
24
from unittest import mock
25
25
-
from rich.pretty import pprint
26
25
27
26
from .confirm import ConfirmOreo
28
27
+287
-285
packages/bundle/bundle/bundle.py
Reviewed
···
22
22
import hydrox.typing as ht
23
23
from jugulis import funcdict, Hydreigon, Deino, iscallableclass
24
24
import re
25
25
-
from functools import partial, cached_property, reduce, cache
25
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
37
-
from rich.console import Console
37
37
+
from uuid import uuid4
38
38
39
39
# TODO: Should `__qualname__` be checked as well if it has no `.`?
40
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
44
-
return self[attr]
45
45
+
if attr in self:
46
46
+
return self[attr]
47
47
+
raise AttributeError()
45
48
46
49
47
50
class bundler(Bundles):
48
48
-
def __init__(self, start, stop, *types, name="f", shared_name="g"):
51
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
58
-
tn = get_name(self.types[0])
59
59
-
exec(
60
60
-
f"@bundle\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...",
61
61
-
locals=ChainMap(self, {"bundle": bundle}),
62
62
-
)
63
63
-
exec(
64
64
-
f"@{self.name}.up\n@bundle\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...",
65
65
-
locals=ChainMap(self, {"bundle": bundle}),
66
66
-
)
67
67
-
exec(
68
68
-
f"@{self.name}.up\n@bundle\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...",
69
69
-
locals=ChainMap(self, {"bundle": bundle}),
70
70
-
)
71
71
-
for t in self.types[1:]:
72
72
-
tn = get_name(t)
61
61
+
if starter:
62
62
+
self.update(starter)
63
63
+
self.root = self[self.name]
64
64
+
else:
65
65
+
tn = get_name(self.types[0])
73
66
exec(
74
74
-
f"@{self.name}.up\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...",
75
75
-
locals=self,
67
67
+
f"@bundle\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...",
68
68
+
locals=ChainMap(self, {"bundle": bundle}),
76
69
)
77
70
exec(
78
78
-
f"@{self.name}.up\n@{self.under_share}.up\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...",
71
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
82
-
f"@{self.name}.up\n@{self.dunder_share}.up\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...",
75
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
85
-
self.root = self[self.name]
86
86
-
self.init(self.name)
78
78
+
for t in self.types[1:]:
79
79
+
tn = get_name(t)
80
80
+
exec(
81
81
+
f"@{self.name}.up\ndef {self.name}({tn[0]}: {tn}) -> {tn}: ...",
82
82
+
locals=self,
83
83
+
)
84
84
+
exec(
85
85
+
f"@{self.name}.up\n@{self.under_share}.up\ndef {self.under_share}({tn[0]}: {tn}) -> {tn}: ...",
86
86
+
locals=ChainMap(self, {"bundle": bundle}),
87
87
+
)
88
88
+
exec(
89
89
+
f"@{self.name}.up\n@{self.dunder_share}.up\ndef {self.dunder_share}({tn[0]}: {tn}) -> {tn}: ...",
90
90
+
locals=ChainMap(self, {"bundle": bundle}),
91
91
+
)
92
92
+
self.root = self[self.name]
93
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
131
-
def functions(self):
138
138
+
def deinos(self):
132
139
return Bundles(
133
140
reduce(
134
141
dict.__or__,
135
142
(
136
143
{
137
137
-
k + get_name(d.__signature__.return_annotation)[0]: d.__func__
138
138
-
for d in v.func
144
144
+
k + get_name(d.__signature__.return_annotation)[0]: d
145
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
153
+
def functions(self):
154
154
+
return Bundles({k: v.__func__ for k, v in self.deinos.items()})
155
155
+
156
156
+
@cached_property
146
157
def function_lists(self):
147
158
return Bundles(
148
159
reduce(
149
160
dict.__or__,
150
150
-
({k: [d.__func__ for d in v.func]} for k, v in self.items()),
161
161
+
({k: [d.__func__ for d in v.funcs]} for k, v in self.items()),
151
162
)
152
163
)
153
164
154
154
-
@cache
155
155
-
def type(self, *types):
156
156
-
bundles = Bundles(
157
157
-
{
158
158
-
k: bundle(*[self.functions[k + get_name(t)[0]] for t in types])
159
159
-
for k in self
160
160
-
}
165
165
+
def filter_types(self, n, b, types, root):
166
166
+
for t in types:
167
167
+
d = self.deinos[n + get_name(t)[0]]
168
168
+
if d in b.funcs:
169
169
+
b.funcs.remove(d)
170
170
+
b.func = self.deinos[n + get_name(root)[0]]
171
171
+
for k, v in b.items():
172
172
+
self.filter_types(k, v, types, root)
173
173
+
return b
174
174
+
175
175
+
def copy(self):
176
176
+
return self.__class__(
177
177
+
self.start,
178
178
+
self.stop,
179
179
+
*self.types,
180
180
+
name=self.name,
181
181
+
shared_name=self.shared_name,
182
182
+
starter={k: v.copy() for k, v in self.items()},
161
183
)
162
162
-
bundles[self.name].up(bundles[self.under_share])
163
163
-
bundles[self.name].up(bundles[self.dunder_share])
184
184
+
185
185
+
def type(self, *types):
186
186
+
bundles = self.copy()
164
187
for k, v in bundles.items():
165
165
-
if k.startswith(self.name) and k != self.name:
166
166
-
bundles[k[0:-1]].up(v)
167
167
-
v.up(bundles[k.replace(self.name, self.shared_name)[0:-1]])
188
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
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
188
-
bundles[name] = type(name, bases, namespace)
208
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
239
+
for n in ns:
240
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
325
+
326
326
+
@staticmethod
327
327
+
def name_is_bundled(name):
328
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
583
+
# * If I decide that children can be nameless, give them a "hidden" name so they aren't overidden;
584
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
571
-
func, *bases = funcs[1]
572
572
-
result = func.append(funcs[2], **kwargs)
573
573
-
for base in bases:
574
574
-
base.append(result, **kwargs)
575
575
-
return result
599
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
578
-
579
579
-
@property
580
580
-
def __name__(self):
581
581
-
return self.__click_kwargs__.get("name", self.func.__name__)
582
582
-
583
583
-
@__name__.setter
584
584
-
def __name__(self, value):
585
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
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
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
619
-
def dunder_check(self, attr):
620
620
-
return not attr.startswith("__") or attr in ("__init__",)
621
621
-
622
637
def process_click_kwargs(self, func, *click_kwargs):
623
623
-
return Dict(
624
624
-
{"name": getattr(func, "__name__", "")}
625
625
-
| getattr(func, "__click_kwargs__", {})
626
626
-
) | reduce(Dict.__or__, click_kwargs)
638
638
+
click_kwargs = reduce(
639
639
+
Dict.__or__, click_kwargs, getattr(func, "__click_kwargs__", {})
640
640
+
)
641
641
+
if not click_kwargs.get("name"):
642
642
+
click_kwargs["name"] = getattr(func, "__name__", self.make_name())
643
643
+
return click_kwargs
627
644
628
628
-
def process_func(self, func, *click_kwargs):
629
629
-
fclick_kwargs = self.process_click_kwargs(func, *click_kwargs)
630
630
-
fname = fclick_kwargs["name"]
631
631
-
if not self.__name__ and fname:
632
632
-
self.__name__ = fname
633
633
-
return fclick_kwargs
645
645
+
def make_name(self):
646
646
+
return f"__bundle_{str(uuid4()).split('-')[0]}__"
634
647
635
635
-
# TODO: Simplify and combine the various functions.
636
636
-
def pre_process_extend(self, func=None, *funcs, **click_kwargs):
637
637
-
fclick_kwargs_list = []
638
638
-
new_funcs = []
639
639
-
for f in (func, *funcs):
640
640
-
if isclass(f):
641
641
-
if funcs:
642
642
-
for k in dir(f):
643
643
-
if self.dunder_check(k):
644
644
-
v = getattr(f, k)
645
645
-
fclick_kwargs_list.append(
646
646
-
self.process_func(
647
647
-
v,
648
648
-
click_kwargs,
649
649
-
{"name": f.__name__ if k == "__init__" else k},
650
650
-
)
651
651
-
)
652
652
-
new_funcs.append(v)
653
653
-
else:
654
654
-
fclick_kwargs_list.append(self.process_func(f, click_kwargs))
655
655
-
new_funcs.append(f)
648
648
+
def make_deino(self, func: abc.Callable) -> Deino:
649
649
+
return Deino(func, **self.deino_kwargs)
650
650
+
651
651
+
def get_func_name(self, func):
652
652
+
return getattr(func, "__click_kwargs__", {}).get(
653
653
+
"name", getattr(func, "__name__", "")
654
654
+
)
655
655
+
656
656
+
def __init__(self, func=None, *funcs, debug=False, **click_kwargs):
657
657
+
self.debug = debug
658
658
+
# TODO
659
659
+
if isinstance(func, str):
660
660
+
self.__name__ = getattr(
661
661
+
click_kwargs,
662
662
+
"pop" if funcs or not getattr(func, "__name__", "") else "get",
663
663
+
)("name", func)
664
664
+
665
665
+
else:
666
666
+
super().__init__()
667
667
+
self.deino_kwargs = {
668
668
+
"default_va_annotation": typing.Any,
669
669
+
"default_vk_annotation": typing.Any,
670
670
+
}
671
671
+
self.func = None
672
672
+
self.funcs = Hydreigon(**self.deino_kwargs)
673
673
+
if "name" in click_kwargs:
674
674
+
self.__name__ = getattr(
675
675
+
click_kwargs,
676
676
+
"pop" if funcs else "get",
677
677
+
)("name")
656
678
else:
657
657
-
match f:
658
658
-
case bundle():
659
659
-
fclick_kwargs_list.append(self.process_func(f, click_kwargs))
660
660
-
new_funcs.append(f)
661
661
-
case dict():
662
662
-
if funcs:
663
663
-
for k, v in f.items():
664
664
-
if self.dunder_check(k):
665
665
-
fclick_kwargs_list.append(
666
666
-
self.process_func(v, click_kwargs, {"name": k})
667
667
-
)
668
668
-
new_funcs.append(v)
669
669
-
else:
670
670
-
fclick_kwargs_list.append(
671
671
-
self.process_func(f, click_kwargs)
672
672
-
)
673
673
-
new_funcs.append(f)
674
674
-
case Hydreigon():
675
675
-
...
676
676
-
case Collection():
677
677
-
if funcs:
678
678
-
for item in f:
679
679
-
fclick_kwargs_list.append(
680
680
-
self.process_func(item, click_kwargs)
681
681
-
)
682
682
-
new_funcs.append(item)
683
683
-
else:
684
684
-
fclick_kwargs_list.append(
685
685
-
self.process_func(f, click_kwargs)
686
686
-
)
687
687
-
new_funcs.append(f)
688
688
-
case _:
689
689
-
fclick_kwargs_list.append(self.process_func(f, click_kwargs))
690
690
-
new_funcs.append(f)
691
691
-
func, *funcs = new_funcs
692
692
-
result = self.append(func, processed_click_kwargs=fclick_kwargs_list[0])
693
693
-
for f, kwargs in zip(funcs, fclick_kwargs_list[1:]):
694
694
-
result.append(f, processed_click_kwargs=kwargs)
695
695
-
return result
679
679
+
for f in (func, *funcs):
680
680
+
if fname := self.get_func_name(f):
681
681
+
self.__name__ = fname
682
682
+
break
683
683
+
else:
684
684
+
self.__name__ = self.make_name()
685
685
+
self.funcs.__name__ = self.__name__
686
686
+
self.__click_kwargs__ = Dict()
687
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
702
-
return self.pre_process_extend(func, *funcs, **click_kwargs)
694
694
+
return self.append(func, *funcs, **click_kwargs)
703
695
704
696
return wrapper
705
705
-
706
706
-
return self.pre_process_extend(*funcs, **click_kwargs)
697
697
+
return self.append(*funcs, **click_kwargs)
707
698
return Bundle.up(self, *funcs, **click_kwargs)
708
699
709
709
-
extend = up
710
710
-
roar = up
700
700
+
def dunder_check(self, attr):
701
701
+
return not attr.startswith("__") or attr in ("__init__",)
711
702
712
712
-
def __init__(self, func=None, *funcs, **click_kwargs):
713
713
-
if not isinstance(func, str):
714
714
-
super().__init__()
715
715
-
self.func = Hydreigon(
716
716
-
default_va_annotation=typing.Any, default_vk_annotation=typing.Any
717
717
-
)
718
718
-
self.__click_kwargs__ = Dict(click_kwargs)
719
719
-
if funcs:
720
720
-
click_kwargs.pop("name", None)
721
721
-
self.up(func, *funcs, **click_kwargs)
703
703
+
def init_swap(self, attr, name=None):
704
704
+
name = self.__name__ if name is None else name
705
705
+
return name if attr == "__init__" else attr
722
706
723
723
-
def process_append(self, func, fname, child):
724
724
-
if child:
725
725
-
if fname in self:
726
726
-
result = self[fname]
727
727
-
exists = True
728
728
-
else:
729
729
-
result = self
730
730
-
exists = False
731
731
-
else:
732
732
-
result = self
733
733
-
exists = True
734
734
-
if isclass(func):
735
735
-
if not exists:
736
736
-
self[fname] = result = bundle(name=fname)
737
737
-
for name in dir(func):
738
738
-
if self.dunder_check(name):
739
739
-
result.append(
740
740
-
getattr(func, name), name=fname if name == "__init__" else name
741
741
-
)
707
707
+
def append(self, func=None, *funcs, **click_kwargs):
708
708
+
if funcs:
709
709
+
for f in (func, *funcs):
710
710
+
self.append(f)
711
711
+
return self
742
712
else:
743
743
-
match func:
744
744
-
case dict():
745
745
-
if not exists:
746
746
-
self[fname] = result = bundle(name=fname)
747
747
-
for name, attr in func.items():
748
748
-
if self.dunder_check(name):
749
749
-
result.append(attr, name=name)
750
750
-
case Hydreigon():
751
751
-
if exists:
752
752
-
result.func.extend(func)
713
713
+
click_kwargs = self.process_click_kwargs(func, click_kwargs)
714
714
+
name = click_kwargs.name
715
715
+
if name in (self.__name__, "__init__"):
716
716
+
self.__click_kwargs__ |= click_kwargs
717
717
+
if func is not None:
718
718
+
if isclass(func):
719
719
+
for k in dir(func):
720
720
+
if self.dunder_check(k):
721
721
+
self.append(
722
722
+
getattr(func, k), name=self.init_swap(k, name)
723
723
+
)
753
724
else:
754
754
-
self[fname] = result = bundle(name=fname)
755
755
-
result.func = func
725
725
+
match func:
726
726
+
case bundle():
727
727
+
self |= func
728
728
+
case dict():
729
729
+
for k, v in func.items():
730
730
+
if self.dunder_check(k):
731
731
+
self.append(v, name=self.init_swap(k, name))
732
732
+
case Hydreigon():
733
733
+
self.funcs += func
734
734
+
case Collection():
735
735
+
for item in func:
736
736
+
self.append(item)
737
737
+
case _:
738
738
+
self.funcs.append(func)
739
739
+
if not self.func:
740
740
+
# NOTE: This needs to be created separately if I want
741
741
+
# the function arguments to be type checked.
742
742
+
self.func = self.make_deino(func)
743
743
+
return self
756
744
757
757
-
# TODO
758
758
-
# case ht.Coll():
759
759
-
# case abc.Iterable():
760
760
-
case Collection():
761
761
-
if not exists:
762
762
-
self[fname] = result = bundle(name=fname)
763
763
-
for f in func:
764
764
-
if isclass(f):
765
765
-
for name in dir(f):
766
766
-
if self.dunder_check(name):
767
767
-
result.append(
768
768
-
getattr(f, name),
769
769
-
name=f.__name__ if name == "__init__" else name,
770
770
-
)
771
771
-
else:
772
772
-
match f:
773
773
-
case bundle():
774
774
-
result.append(f)
775
775
-
case dict():
776
776
-
for name, attr in f.items():
777
777
-
if self.dunder_check(name):
778
778
-
result.append(attr, name=name)
779
779
-
# case Hydreigon():
780
780
-
# ...
781
781
-
# case Collection():
782
782
-
# ...
783
783
-
case _:
784
784
-
result.append(f)
745
745
+
# TODO: How do I deal with names and kwargs?
746
746
+
elif isinstance(func, bundle):
747
747
+
self[name] = func.copy()
785
748
786
786
-
case _:
787
787
-
if exists:
788
788
-
result.func.append(func)
749
749
+
elif self.__class__.name_is_bundled(name):
750
750
+
if func is not None:
751
751
+
if isclass(func):
752
752
+
for k in dir(func):
753
753
+
if self.dunder_check(k):
754
754
+
v = getattr(func, k)
755
755
+
k = self.init_swap(k, name)
756
756
+
if k in self:
757
757
+
self[k].append(v, name=k)
758
758
+
else:
759
759
+
self[k] = bundle(v, name=k)
789
760
else:
790
790
-
self[fname] = result = bundle(func, name=fname)
791
791
-
792
792
-
return result
793
793
-
794
794
-
def append(self, func=None, /, processed_click_kwargs=None, **click_kwargs):
795
795
-
click_kwargs = (
796
796
-
self.process_click_kwargs(func, click_kwargs)
797
797
-
if processed_click_kwargs is None
798
798
-
else processed_click_kwargs
799
799
-
)
800
800
-
if not (fname := click_kwargs.get("name")):
801
801
-
click_kwargs["name"] = fname = getattr(func, "__name__", "")
802
802
-
if fname in (self.__name__, "__init__"):
803
803
-
self.__click_kwargs__ |= click_kwargs
804
804
-
if func is not None:
805
805
-
if not isinstance(func, bundle):
806
806
-
return self.process_append(func, fname, False)
807
807
-
808
808
-
# NOTE: At any given moment, there can be only one instance of `self`,
809
809
-
# i.e., only one version of this command.
810
810
-
# TODO: Not necessarily, as the result can be assigned to a variable with another name.
811
811
-
# Therefore, find a way to update the old version of func as well.
812
812
-
# TODO: ... Wouldn't `func` be updated anyway, as `self = func`?
813
813
-
self |= func
814
814
-
815
815
-
return self
816
816
-
817
817
-
if fname:
818
818
-
if isinstance(func, bundle):
819
819
-
# NOTE: At any given moment, there can be only one instance of `fname`,
820
820
-
# i.e., only one version of this command.
821
821
-
# TODO: Not necessarily, as the result can be assigned to a variable with another name.
822
822
-
# Therefore, find a way to update the old version of func as well.
823
823
-
# TODO: ... Wouldn't `func` be updated anyway `if fname in self`, as `self[fname] = func`?
824
824
-
if fname in self:
825
825
-
self[fname] |= func
761
761
+
match func:
762
762
+
case dict():
763
763
+
for k, v in func.items():
764
764
+
if self.dunder_check(k):
765
765
+
k = self.init_swap(k, name)
766
766
+
if k in self:
767
767
+
self[k].append(v, name=k)
768
768
+
else:
769
769
+
self[k] = bundle(v, name=k)
770
770
+
case Hydreigon():
771
771
+
self.funcs += func
772
772
+
case Collection():
773
773
+
for item in func:
774
774
+
self.append(item)
775
775
+
case _:
776
776
+
self.funcs.append(func)
777
777
+
if not self.func:
778
778
+
# NOTE: This needs to be created separately if I want
779
779
+
# the function arguments to be type checked.
780
780
+
self.func = self.make_deino(func)
781
781
+
return self
782
782
+
elif func is None:
783
783
+
if name in self:
784
784
+
self[name].__click_kwargs__ |= click_kwargs
826
785
else:
827
827
-
self[fname] = func
828
828
-
return self[fname]
829
829
-
830
830
-
if func is None:
831
831
-
if fname in self:
832
832
-
return self[fname]
833
833
-
self[fname] = result = bundle(**click_kwargs)
834
834
-
return result
835
835
-
return self.process_append(func, fname, True)
786
786
+
self[name] = bundle(**click_kwargs)
787
787
+
elif isclass(func):
788
788
+
if name in self:
789
789
+
result = self[name]
790
790
+
result.__click_kwargs__ |= click_kwargs
791
791
+
else:
792
792
+
self[name] = result = bundle(**click_kwargs)
793
793
+
for k in dir(func):
794
794
+
if self.dunder_check(k):
795
795
+
result.append(getattr(func, k), name=self.init_swap(k, name))
796
796
+
else:
797
797
+
match func:
798
798
+
case dict():
799
799
+
if name in self:
800
800
+
result = self[name]
801
801
+
result.__click_kwargs__ |= click_kwargs
802
802
+
else:
803
803
+
self[name] = result = bundle(**click_kwargs)
804
804
+
for k, v in func.items():
805
805
+
if self.dunder_check(k):
806
806
+
result.append(v, name=self.init_swap(k, name))
807
807
+
case Hydreigon():
808
808
+
if name in self:
809
809
+
self[name].funcs += func
810
810
+
self[name].__click_kwargs__ |= click_kwargs
811
811
+
else:
812
812
+
self[name] = bundle(func, **click_kwargs)
813
813
+
case Collection():
814
814
+
if name in self:
815
815
+
result = self[name]
816
816
+
result.__click_kwargs__ |= click_kwargs
817
817
+
else:
818
818
+
self[name] = result = bundle(**click_kwargs)
819
819
+
for item in func:
820
820
+
result.append(func)
821
821
+
case _:
822
822
+
if name in self:
823
823
+
self[name].append(func, **click_kwargs)
824
824
+
else:
825
825
+
self[name] = bundle(func, **click_kwargs)
826
826
+
return self[name]
836
827
837
828
def __rich_repr__(self):
838
838
-
yield self.__name__
839
839
-
yield self.func
840
840
-
yield dict(self)
829
829
+
yield getattr(
830
830
+
self.func,
831
831
+
"__name__",
832
832
+
"main" if self.__class__.name_is_bundled(self.__name__) else self.__name__,
833
833
+
)
834
834
+
yield "command", self.__name__
835
835
+
yield "root", self.func
836
836
+
yield "functions", self.funcs
837
837
+
yield "subcommands", dict(self)
841
838
842
839
def update(self, other):
843
840
if isinstance(other, self.__class__):
844
844
-
self.func += other.func
841
841
+
other = other.copy()
842
842
+
self.func = other.func
843
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
850
-
# TODO: This will make the result a rootless application.
851
851
-
# Do I want that?
852
849
def copy(self):
853
853
-
result = self.__class__(self)
854
854
-
result.func = self.func.copy()
850
850
+
result = self.__class__(**self.__click_kwargs__)
851
851
+
for k, v in self.items():
852
852
+
result[k] = v.copy()
853
853
+
result.func = self.func.copy() if self.func else None
854
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
880
-
def compile(self, parent=click, *, click_kwargs=None, only_params=True):
881
881
-
hydreigon: Hydreigon
882
882
-
deino: Deino
883
883
-
func: abc.Callable
884
884
-
if self.func:
885
885
-
hydreigon = self.func
886
886
-
else:
887
887
-
hydreigon = Hydreigon(lambda: None)
888
888
-
deino: Deino = hydreigon[0]
889
889
-
func = deino.__func__
880
880
+
def compile(self, parent=click, *, name=None, click_kwargs=None, only_params=True):
881
881
+
if name is None:
882
882
+
name = (
883
883
+
"main"
884
884
+
if self.__class__.name_is_bundled(self.__name__)
885
885
+
else self.__name__
886
886
+
)
887
887
+
deino: Deino = self.func or self.make_deino(lambda: None)
888
888
+
func: abc.Callable = deino.__func__
890
889
bundled_args = defaultdict(
891
890
list,
892
892
-
getattr(hydreigon, "__bundled_args__", {})
893
893
-
| getattr(deino, "__bundled_args__", {})
891
891
+
getattr(deino, "__bundled_args__", {})
894
892
| getattr(func, "__bundled_args__", {}),
895
893
)
896
894
bundled_kwargs = Dict(
897
897
-
getattr(hydreigon, "__bundled_kwargs__", {})
898
898
-
| getattr(deino, "__bundled_kwargs__", {})
895
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
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
932
-
for name in param_keys - {param.name for param in click_params}:
933
933
-
param: Parameter = params[name]
928
928
+
for param_name in param_keys - {param.name for param in click_params}:
929
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
948
-
*self.process_names(name, kind, bundled_args[name], click_params),
944
944
+
*self.process_names(
945
945
+
param_name, kind, bundled_args[param_name], click_params
946
946
+
),
949
947
**self.__class__.process_kwargs(
950
950
-
name, param, bundled_kwargs[name], docstring_params[name]
948
948
+
param_name,
949
949
+
param,
950
950
+
bundled_kwargs[param_name],
951
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
979
-
| {"name": self.__name__}
980
980
| dockwargs
981
981
| self.__click_kwargs__
982
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
987
-
for v in self.values():
988
988
-
v.compile(group, click_kwargs=click_kwargs)
988
988
+
for k, v in self.items():
989
989
+
if not self.__class__.name_is_bundled(k):
990
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
995
-
self.func.raise_if_empty()
996
996
-
return self.func.invoke(*args, **kwargs)
997
997
+
self.funcs.raise_if_empty()
998
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
1007
-
self.func.raise_if_empty()
1008
1008
-
return self.func[0]
1009
1009
+
self.funcs.raise_if_empty()
1010
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
Reviewed
···
302
302
pprint(b3)
303
303
304
304
names = (b1.__name__, b2.__name__, b3.__name__)
305
305
-
assert not any(names)
305
305
+
assert all(map(bundle.name_is_bundled, names))
306
306
assert integers.f.__name__ not in names
307
307
308
308
-
funcs = (b1.func, b2.func, b3.func)
308
308
+
funcs = (b1.funcs, b2.funcs, b3.funcs)
309
309
assert not any(funcs)
310
310
-
assert integers.f.func not in funcs
310
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
438
+
pprint(bundles.f1)
439
439
+
pprint(strings.f1)
440
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
454
-
assert bundles.f1.func == f1.func
455
455
-
assert strings.f1.func != f1.func
456
456
-
assert bundles.f11.func != f1.f11.func
457
457
-
assert bundles.f12.func != f1.f12.func
458
458
-
assert strings.f11.func == f1.f11.func
459
459
-
assert strings.f12.func == f1.f12.func
457
457
+
assert bundles.f1.funcs == f1.funcs
458
458
+
assert strings.f1.funcs != f1.funcs
459
459
+
assert bundles.f11.funcs != f1.f11.funcs
460
460
+
assert bundles.f12.funcs != f1.f12.funcs
461
461
+
assert strings.f11.funcs == f1.f11.funcs
462
462
+
assert strings.f12.funcs == f1.f12.funcs
460
463
461
464
def test_root_decorated_child_inherited_class(self, bundles, strings, functions):
465
465
+
pprint(bundles.f1)
466
466
+
462
467
@bundle
463
468
class f1:
464
469
__init__ = functions.f1i
···
474
479
475
480
pprint(f1)
476
481
477
477
-
assert bundles.f1.func != f1.func
478
478
-
assert strings.f1.func == f1.func
479
479
-
assert bundles.f11.func == f1.f11.func
480
480
-
assert bundles.f12.func == f1.f12.func
481
481
-
assert strings.f11.func != f1.f11.func
482
482
-
assert strings.f12.func != f1.f12.func
482
482
+
assert bundles.f1.funcs != f1.funcs
483
483
+
assert strings.f1.funcs == f1.funcs
484
484
+
assert bundles.f11.funcs == f1.f11.funcs
485
485
+
assert bundles.f12.funcs == f1.f12.funcs
486
486
+
assert strings.f11.funcs != f1.f11.funcs
487
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
Reviewed
···
1
1
+
from bundle import bundler
2
2
+
3
3
+
bundles = bundler(1, 2)
4
4
+
functions = bundles.functions
5
5
+
deinos = bundles.deinos
6
6
+
integers = bundles.type(int)
7
7
+
strings = bundles.type(str)
8
8
+
9
9
+
assert hash(bundles) == hash(bundles.copy())
+1
-1
packages/jugulis/jugulis/__init__.py
Reviewed
···
1
1
from .deino import Deino, format_message
2
2
from .hydreigon import Hydreigon, AmbiguityError, AvailabilityError
3
3
-
from .jugulis import funcdict, Jugulis, jugulis, IronJugulis, IronJugudict
3
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
Reviewed
···
35
35
36
36
37
37
# TODO: What happens if you initialize with a Deino?
38
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
92
+
def copy(self):
93
93
+
return self.__class__(
94
94
+
self.__func__,
95
95
+
cache=self.__cache__,
96
96
+
evolved=self.__evolved__,
97
97
+
default_annotation=self.__default_annotation__,
98
98
+
default_va_annotation=self.__default_va_annotation__,
99
99
+
default_vk_annotation=self.__default_vk_annotation__,
100
100
+
precedence=self.__precedence__,
101
101
+
hashed=self.__hashed__,
102
102
+
cls=self.__cls__,
103
103
+
)
104
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
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
119
+
self.__class__.__name__,
106
120
self.__func__,
107
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
Reviewed
···
182
182
def copy(self):
183
183
result = self.ecopy()
184
184
result.__name__ = self.__name__
185
185
-
super(self.__class__, result).extend(self)
185
185
+
super(self.__class__, result).extend(d.copy() for d in self)
186
186
return result
187
187
188
188
def ecopy(self):