Coverage for / home / ubuntu / lunchbox / python / lunchbox / infix.py: 100%
168 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-26 04:02 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-26 04:02 +0000
1from typing import Any, Callable # noqa F401
2# ------------------------------------------------------------------------------
5class InfixBase:
6 '''
7 InfixBase is used for declaring a mapping between infix operators and class
8 methods, using _infix_lookup.
9 '''
10 def __init__(self, *args, **kwargs):
11 # type: (*Any, **Any) -> None
12 '''
13 Construct Infix instance.
14 '''
15 self._infix_lookup = {} # type: dict[str, str]
17 def _get_infix_function(self, symbol):
18 # type: (str) -> Callable
19 '''
20 Get infix function from lookup table.
22 Args:
23 symbol (str): Lookup table symbol.
25 Returns:
26 callable: Infix function.
27 '''
28 name = self._infix_lookup.get(symbol, '')
29 try:
30 return getattr(self, name)
31 except AttributeError:
32 msg = f"Method not implemented for '{symbol}'."
33 if name != '':
34 msg = f"Method {name} not implemented for '{symbol}'."
35 raise NotImplementedError(msg)
38class ArithmeticInfix(InfixBase):
39 '''
40 Infix class for infix operators: +, -, *, /
41 '''
42 def __init__(self, *args, **kwargs):
43 # type: (*Any, **Any) -> None
44 '''
45 Construct ArithmeticInfix instance.
46 '''
47 super().__init__()
48 self._infix_lookup.update({
49 '+': '', # add
50 'r+': '', # add
51 '-': '', # subtract
52 'r-': '', # subtract
53 '*': '', # multiply
54 'r*': '', # multiply
55 '/': '', # divide
56 'r/': '', # divide
57 })
59 def __add__(self, value):
60 # type: (Any) -> Any
61 '''
62 Add (+).
64 Args:
65 value (object): Value.
67 Returns:
68 object: Self ADD value.
69 '''
70 return self._get_infix_function('+')(value)
72 def __radd__(self, value):
73 # type: (Any) -> Any
74 '''
75 Add (+).
77 Args:
78 value (object): Value.
80 Returns:
81 object: Value ADD self.
82 '''
83 return self._get_infix_function('r+')(value)
85 def __sub__(self, value):
86 # type: (Any) -> Any
87 '''
88 Subtract (-).
90 Args:
91 value (object): Value.
93 Returns:
94 object: Self SUBTRACT value.
95 '''
96 return self._get_infix_function('-')(value)
98 def __rsub__(self, value):
99 # type: (Any) -> Any
100 '''
101 Subtract (-).
103 Args:
104 value (object): Value.
106 Returns:
107 object: Value SUBTRACT self.
108 '''
109 return self._get_infix_function('r-')(value)
111 def __mul__(self, value):
112 # type: (Any) -> Any
113 '''
114 Multiply (*).
116 Args:
117 value (object): Value.
119 Returns:
120 object: Self MULTIPLY value.
121 '''
122 return self._get_infix_function('*')(value)
124 def __rmul__(self, value):
125 # type: (Any) -> Any
126 '''
127 Multiply (*).
129 Args:
130 value (object): Value.
132 Returns:
133 object: Value MULTIPLY self.
134 '''
135 return self._get_infix_function('r*')(value)
137 def __truediv__(self, value):
138 # type: (Any) -> Any
139 '''
140 Divide (/).
142 Args:
143 value (object): Value.
145 Returns:
146 object: Self DIVIDE value.
147 '''
148 return self._get_infix_function('/')(value)
150 def __rtruediv__(self, value):
151 # type: (Any) -> Any
152 '''
153 Divide (/).
155 Args:
156 value (object): Value.
158 Returns:
159 object: Value DIVIDE self.
160 '''
161 return self._get_infix_function('r/')(value)
164class MathInfix(InfixBase):
165 def __init__(self, *args, **kwargs):
166 # type: (*Any, **Any) -> None
167 '''
168 Infix class for infix operators: %, //, **, @
169 '''
170 super().__init__()
171 self._infix_lookup.update({
172 '%': '', # modulo
173 'r%': '', # modulo
174 '//': '', # floor divide
175 'r//': '', # floor divide
176 '**': '', # exponentiate
177 'r**': '', # exponentiate
178 '@': '', # matrix multiply
179 'r@': '', # matrix multiply
180 })
182 def __mod__(self, value):
183 # type: (Any) -> Any
184 '''
185 Modulo (%).
187 Args:
188 value (object): Value.
190 Returns:
191 object: Self MODULO value.
192 '''
193 return self._get_infix_function('%')(value)
195 def __rmod__(self, value):
196 # type: (Any) -> Any
197 '''
198 Modulo (%).
200 Args:
201 value (object): Value.
203 Returns:
204 object: Value MODULO self.
205 '''
206 return self._get_infix_function('r%')(value)
208 def __floordiv__(self, value):
209 # type: (Any) -> Any
210 '''
211 Floor divide (//).
213 Args:
214 value (object): Value.
216 Returns:
217 object: Self FLOOR DIVIDE value.
218 '''
219 return self._get_infix_function('//')(value)
221 def __rfloordiv__(self, value):
222 # type: (Any) -> Any
223 '''
224 Floor divide (//).
226 Args:
227 value (object): Value.
229 Returns:
230 object: Value FLOOR DIVIDE self.
231 '''
232 return self._get_infix_function('r//')(value)
234 def __pow__(self, value):
235 # type: (Any) -> Any
236 '''
237 Exponentiate (**).
239 Args:
240 value (object): Value.
242 Returns:
243 object: Self EXPONENTIATE value.
244 '''
245 return self._get_infix_function('**')(value)
247 def __rpow__(self, value):
248 # type: (Any) -> Any
249 '''
250 Exponentiate (**).
252 Args:
253 value (object): Value.
255 Returns:
256 object: Value EXPONENTIATE self.
257 '''
258 return self._get_infix_function('r**')(value)
260 def __matmul__(self, value):
261 # type: (Any) -> Any
262 '''
263 Matrix multiply (@).
265 Args:
266 value (object): Value.
268 Returns:
269 object: Self MATRIX MULTIPLY value.
270 '''
271 return self._get_infix_function('@')(value)
273 def __rmatmul__(self, value):
274 # type: (Any) -> Any
275 '''
276 Matrix multiply (@).
278 Args:
279 value (object): Value.
281 Returns:
282 object: Value MATRIX MULTIPLY self.
283 '''
284 return self._get_infix_function('r@')(value)
287class LogicInfix(InfixBase):
288 def __init__(self, *args, **kwargs):
289 # type: (*Any, **Any) -> None
290 '''
291 Infix class for infix operators: &, |, ^
292 '''
293 super().__init__()
294 self._infix_lookup.update({
295 '&': '', # and
296 'r&': '', # and
297 '|': '', # or
298 'r|': '', # or
299 '^': '', # exclusive or
300 'r^': '', # exclusive or
301 })
303 def __and__(self, value):
304 # type: (Any) -> Any
305 '''
306 And (&).
308 Args:
309 value (object): Value.
311 Returns:
312 object: Self AND value.
313 '''
314 return self._get_infix_function('&')(value)
316 def __rand__(self, value):
317 # type: (Any) -> Any
318 '''
319 And (&).
321 Args:
322 value (object): Value.
324 Returns:
325 object: Value AND self.
326 '''
327 return self._get_infix_function('r&')(value)
329 def __or__(self, value):
330 # type: (Any) -> Any
331 '''
332 Or (|).
334 Args:
335 value (object): Value.
337 Returns:
338 object: Self OR value.
339 '''
340 return self._get_infix_function('|')(value)
342 def __ror__(self, value):
343 # type: (Any) -> Any
344 '''
345 Or (|).
347 Args:
348 value (object): Value.
350 Returns:
351 object: Value OR self.
352 '''
353 return self._get_infix_function('r|')(value)
355 def __xor__(self, value):
356 # type: (Any) -> Any
357 '''
358 Exclusive or (^).
360 Args:
361 value (object): Value.
363 Returns:
364 object: Self EXCLUSIVE value.
365 '''
366 return self._get_infix_function('^')(value)
368 def __rxor__(self, value):
369 # type: (Any) -> Any
370 '''
371 Exclusive or (^).
373 Args:
374 value (object): Value.
376 Returns:
377 object: Value EXCLUSIVE self.
378 '''
379 return self._get_infix_function('r^')(value)
382class ComparisonInfix(InfixBase):
383 def __init__(self, *args, **kwargs):
384 # type: (*Any, **Any) -> None
385 '''
386 Infix class for infix operators: <, <=, >, >=
387 '''
388 super().__init__()
389 self._infix_lookup.update({
390 '<': '', # less than
391 '<=': '', # less than or equal
392 '>': '', # greater than
393 '>=': '', # greater than or equal
394 })
396 def __lt__(self, value):
397 # type: (Any) -> Any
398 '''
399 Less than (<).
401 Args:
402 value (object): Value.
404 Returns:
405 object: Self LESS THAN value.
406 '''
407 return self._get_infix_function('<')(value)
409 def __le__(self, value):
410 # type: (Any) -> Any
411 '''
412 Less than or equal (.
414 Args:
415 value (object): Value.
417 Returns:
418 object: Self LESS THAN OR EQUAL TO value.
419 '''
420 return self._get_infix_function('<=')(value)
422 def __gt__(self, value):
423 # type: (Any) -> Any
424 '''
425 Greater than (>).
427 Args:
428 value (object): Value.
430 Returns:
431 object: Self GREATER THAN value.
432 '''
433 return self._get_infix_function('>')(value)
435 def __ge__(self, value):
436 # type: (Any) -> Any
437 '''
438 Greater than or equa.
440 Args:
441 value (object): Value.
443 Returns:
444 object: Self GREATER THAN OR EQUAL TO value.
445 '''
446 return self._get_infix_function('>=')(value)
449class BitwiseInfix(InfixBase):
450 def __init__(self, *args, **kwargs):
451 # type: (*Any, **Any) -> None
452 '''
453 Infix class for infix operators: <<, >>
454 '''
455 super().__init__()
456 self._infix_lookup.update({
457 '>>': '', # right bit shift
458 'r>>': '', # right bit shift
459 '<<': '', # left bit shift
460 'r<<': '', # left bit shift
461 })
463 def __rshift__(self, value):
464 # type: (Any) -> Any
465 '''
466 Right bit shift (>>).
468 Args:
469 value (object): Value.
471 Returns:
472 object: Value RIGHT BIT SHIFT self.
473 '''
474 return self._get_infix_function('>>')(value)
476 def __rrshift__(self, value):
477 # type: (Any) -> Any
478 '''
479 Right bit shift (>>).
481 Args:
482 value (object): Value.
484 Returns:
485 object: Value RIGHT BIT SHIFT self.
486 '''
487 return self._get_infix_function('r>>')(value)
489 def __lshift__(self, value):
490 # type: (Any) -> Any
491 '''
492 Left bit shift (<<).
494 Args:
495 value (object): Value.
497 Returns:
498 object: Self LEFT BIT SHIFT value.
499 '''
500 return self._get_infix_function('<<')(value)
502 def __rlshift__(self, value):
503 # type: (Any) -> Any
504 '''
505 Left bit shift (<<).
507 Args:
508 value (object): Value.
510 Returns:
511 object: Value LEFT BIT SHIFT self.
512 '''
513 return self._get_infix_function('r<<')(value)
516class ItemInfix(InfixBase):
517 def __init__(self, *args, **kwargs):
518 # type: (*Any, **Any) -> None
519 '''
520 Infix class for infix operators: [], [] =, del [], [missing]
521 '''
522 super().__init__()
523 self._infix_lookup.update({
524 '[]': '', # get item
525 '[] =': '', # set item
526 '[missing]': '', # missing item
527 'del []': '', # delete item
528 })
530 def __getitem__(self, key):
531 # type: (Any) -> Any
532 '''
533 Get item ([]).
535 Args:
536 key (object): Key.
538 Returns:
539 object: Self GET ITEM key.
540 '''
541 try:
542 return self._get_infix_function('[]')(key)
543 except KeyError:
544 return self.__missing__(key)
546 def __setitem__(self, key, value):
547 # type: (Any, Any) -> Any
548 '''
549 Set item (x[key] = value).
551 Args:
552 key (object): Key.
553 value (object): Value.
555 Returns:
556 object: Self SET ITEM value.
557 '''
558 return self._get_infix_function('[] =')(key, value)
560 def __missing__(self, key):
561 # type: (Any) -> Any
562 '''
563 Missing item ([]). When __getitem__ looks for a non-existent key.
565 Args:
566 key (object): Key.
568 Returns:
569 object: Self MISSING key.
570 '''
571 return self._get_infix_function('[missing]')(key)
573 def __delitem__(self, key):
574 # type: (Any) -> Any
575 '''
576 Delete item (del x[key]).
578 Args:
579 key (object): Key.
581 Returns:
582 object: Self DELETE key.
583 '''
584 return self._get_infix_function('del []')(key)
587class UnaryInfix(InfixBase):
588 def __init__(self, *args, **kwargs):
589 # type: (*Any, **Any) -> None
590 '''
591 Infix class for unary operators: ~, -, +
592 '''
593 super().__init__()
594 self._infix_lookup.update({
595 '~': '', # invert
596 'x-': '', # negative
597 'x+': '', # positive
598 })
600 def __invert__(self):
601 # type: () -> Any
602 '''
603 Invert (~).
605 Returns:
606 object: INVERT self.
607 '''
608 return self._get_infix_function('~')()
610 def __neg__(self):
611 # type: () -> Any
612 '''
613 Negative (-).
615 Returns:
616 object: NEGATIVE self.
617 '''
618 return self._get_infix_function('x-')()
620 def __pos__(self):
621 '''
622 Positive (+).
624 Returns:
625 object: POSITIVE self.
626 '''
627 return self._get_infix_function('x+')()
630class EqualityInfix(InfixBase):
631 def __init__(self, *args, **kwargs):
632 # type: (*Any, **Any) -> None
633 '''
634 Infix class for infix operators: ==, !=
635 '''
636 super().__init__()
637 self._infix_lookup.update({
638 '==': '', # equal
639 '!=': '', # not equal
640 })
642 def __eq__(self, value):
643 # type: (Any) -> Any
644 '''
645 Equal (==).
647 Args:
648 value (object): Value.
650 Returns:
651 object: Self EQUAL value.
652 '''
653 return self._get_infix_function('==')(value)
655 def __ne__(self, value):
656 # type: (Any) -> Any
657 '''
658 Not equal (!=).
660 Args:
661 value (object): Value.
663 Returns:
664 object: Self NOT EQUAL value.
665 '''
666 return self._get_infix_function('!=')(value)
669class AssignmentInfix(InfixBase):
670 def __init__(self, *args, **kwargs):
671 # type: (*Any, **Any) -> None
672 '''
673 Infix class for assignment operators: +=, -=, *=, /=, %=, //=, **=, @=,
674 &=, |=, ^=, >>=, <<=
675 '''
676 super().__init__()
677 self._infix_lookup.update({
678 '+=': '', # add and assign
679 '-=': '', # subtract and assign
680 '*=': '', # multiply and assign
681 '/=': '', # divide and assign
682 '%=': '', # modulo and assign
683 '//=': '', # floor divide and assign
684 '**=': '', # pow and assign
685 '@=': '', # matrix multiply and assign
686 '&=': '', # and and assign
687 '|=': '', # or and assign
688 '^=': '', # exclusive or and assign
689 '>>=': '', # right bit shift and assign
690 '<<=': '', # left bit shift and assign
691 })
693 def __iadd__(self, value):
694 # type: (Any) -> Any
695 '''
696 Add and assign (+=).
698 Args:
699 value (object): Value.
701 Returns:
702 object: Assign self ADD value.
703 '''
704 return self._get_infix_function('+=')(value)
706 def __isub__(self, value):
707 # type: (Any) -> Any
708 '''
709 Subtract and assign (-=).
711 Args:
712 value (object): Value.
714 Returns:
715 object: Assign self SUBTRACT value.
716 '''
717 return self._get_infix_function('-=')(value)
719 def __imul__(self, value):
720 # type: (Any) -> Any
721 '''
722 Multiply and assign (*=)
724 Args:
725 value (object): Value.
727 Returns:
728 object: Assign self MULTIPLY value.
729 '''
730 return self._get_infix_function('*=')(value)
732 def __itruediv__(self, value):
733 # type: (Any) -> Any
734 '''
735 Divide and assign (/=).
737 Args:
738 value (object): Value.
740 Returns:
741 object: Assign self DIVIDE value.
742 '''
743 return self._get_infix_function('/=')(value)
745 def __imod__(self, value):
746 # type: (Any) -> Any
747 '''
748 Modulo and assign (%=).
750 Args:
751 value (object): Value.
753 Returns:
754 object: Assign self MODULO value.
755 '''
756 return self._get_infix_function('%=')(value)
758 def __ifloordiv__(self, value):
759 # type: (Any) -> Any
760 '''
761 Floor divide and assign (//=).
763 Args:
764 value (object): Value.
766 Returns:
767 object: Assign self FLOOR value.
768 '''
769 return self._get_infix_function('//=')(value)
771 def __ipow__(self, value):
772 # type: (Any) -> Any
773 '''
774 Exponentiate and assign (**=).
776 Args:
777 value (object): Value.
779 Returns:
780 object: Assign self EXPONENTIATE value.
781 '''
782 return self._get_infix_function('**=')(value)
784 def __imatmul__(self, value):
785 # type: (Any) -> Any
786 '''
787 Matrix multiply and assign (@=).
789 Args:
790 value (object): Value.
792 Returns:
793 n (@object: Assign self MATRIX MULTIPLY value.
794 '''
795 return self._get_infix_function('@=')(value)
797 def __iand__(self, value):
798 # type: (Any) -> Any
799 '''
800 And and assign (&=).
802 Args:
803 value (object): Value.
805 Returns:
806 object: Assign self AND value.
807 '''
808 return self._get_infix_function('&=')(value)
810 def __ior__(self, value):
811 # type: (Any) -> Any
812 '''
813 Or and assign (|=).
815 Args:
816 value (object): Value.
818 Returns:
819 object: Assign self OR value.
820 '''
821 return self._get_infix_function('|=')(value)
823 def __ixor__(self, value):
824 # type: (Any) -> Any
825 '''
826 Exclusive or and assign (^=).
828 Args:
829 value (object): Value.
831 Returns:
832 n (^object: Assign self EXCLUSIVE value.
833 '''
834 return self._get_infix_function('^=')(value)
836 def __irshift__(self, value):
837 # type: (Any) -> Any
838 '''
839 Right bit shift and assign (>>=).
841 Args:
842 value (object): Value.
844 Returns:
845 n (>>object: Assign self RIGHT value.
846 '''
847 return self._get_infix_function('>>=')(value)
849 def __ilshift__(self, value):
850 # type: (Any) -> Any
851 '''
852 Left bit shift and assign (<<=).
854 Args:
855 value (object): Value.
857 Returns:
858 (<object: Assign self LEFT value.
859 '''
860 return self._get_infix_function('<<=')(value)
863class MiscInfix(InfixBase):
864 def __init__(self, *args, **kwargs):
865 # type: (*Any, **Any) -> None
866 '''
867 Infix class for operators: del x.attr, in
868 '''
869 super().__init__()
870 self._infix_lookup.update({
871 'del .': '', # delete attribute
872 'in': '', # contains
873 })
875 def __delattr__(self, value):
876 # type: (Any) -> Any
877 '''
878 Delete attribute (del x.attr).
880 Args:
881 value (object): Value.
883 Returns:
884 object: Self DELETE value.
885 '''
886 return self._get_infix_function('del .')(value)
888 def __contains__(self, value):
889 # type: (Any) -> Any
890 '''
891 Contains (in).
893 Args:
894 value (object): Value.
896 Returns:
897 object: Value CONTAINS self.
898 '''
899 return self._get_infix_function('in')(value)
902class AllInfix(
903 ArithmeticInfix,
904 MathInfix,
905 LogicInfix,
906 ComparisonInfix,
907 BitwiseInfix,
908 ItemInfix,
909 UnaryInfix,
910 EqualityInfix,
911 AssignmentInfix,
912 MiscInfix,
913):
914 r'''
915 Infix class for all of the following operators:
917 ========= =========================== ===============
918 Key Function From Class
919 ========= =========================== ===============
920 \+ add ArithmeticInfix
921 r+ add (right) ArithmeticInfix
922 \- subtract ArithmeticInfix
923 r- subtract (right) ArithmeticInfix
924 \* multiply ArithmeticInfix
925 r\* multiply (right) ArithmeticInfix
926 / divide ArithmeticInfix
927 r/ divide (right) ArithmeticInfix
928 % modulo MathInfix
929 r% modulo (right) MathInfix
930 // floor divide MathInfix
931 r// floor divide (right) MathInfix
932 ** exponentiate MathInfix
933 r** exponentiate (right) MathInfix
934 @ matrix multiply MathInfix
935 r@ matrix multiply (right) MathInfix
936 & and LogicInfix
937 r& and (right) LogicInfix
938 \| or LogicInfix
939 r| or (right) LogicInfix
940 ^ exclusive or LogicInfix
941 r^ exclusive or (right) LogicInfix
942 < less than ComparisonInfix
943 <= less than or equal ComparisonInfix
944 > greater than ComparisonInfix
945 >= greater than or equal ComparisonInfix
946 >> right bit shift BitwiseInfix
947 r>> right bit shift (right) BitwiseInfix
948 << left bit shift BitwiseInfix
949 r<< left bit shift (right) BitwiseInfix
950 [] get item ItemInfix
951 [] = set item ItemInfix
952 [missing] missing item ItemInfix
953 del [] delete item ItemInfix
954 ~ invert UnaryInfix
955 x- negative UnaryInfix
956 x+ positive UnaryInfix
957 == equal EqualityInfix
958 != not equal EqualityInfix
959 += add and assign AssignmentInfix
960 -= subtract and assign AssignmentInfix
961 *= multiply and assign AssignmentInfix
962 /= divide and assign AssignmentInfix
963 %= modulo and assign AssignmentInfix
964 //= floor divide and assign AssignmentInfix
965 **= pow and assign AssignmentInfix
966 @= matrix multiply and assign AssignmentInfix
967 &= and and assign AssignmentInfix
968 |= or and assign AssignmentInfix
969 ^= exclusive or and assign AssignmentInfix
970 >>= right bit shift and assign AssignmentInfix
971 <<= left bit shift and assign AssignmentInfix
972 del . delete attribute MiscInfix
973 in contains MiscInfix
974 ========= =========================== ===============
975 '''
976 pass
979class UtiltyInfix(
980 ArithmeticInfix,
981 MathInfix,
982 LogicInfix,
983 ComparisonInfix,
984 BitwiseInfix,
985 ItemInfix,
986 UnaryInfix,
987):
988 r'''
989 Infix class for all of the following operators:
991 ========= =========================== ===============
992 Key Function From Class
993 ========= =========================== ===============
994 \+ add ArithmeticInfix
995 r+ add (right) ArithmeticInfix
996 \- subtract ArithmeticInfix
997 r- subtract (right) ArithmeticInfix
998 \* multiply ArithmeticInfix
999 r\* multiply (right) ArithmeticInfix
1000 / divide ArithmeticInfix
1001 r/ divide (right) ArithmeticInfix
1002 % modulo MathInfix
1003 r% modulo (right) MathInfix
1004 // floor divide MathInfix
1005 r// floor divide (right) MathInfix
1006 ** exponentiate MathInfix
1007 r** exponentiate (right) MathInfix
1008 @ matrix multiply MathInfix
1009 r@ matrix multiply (right) MathInfix
1010 & and LogicInfix
1011 r& and (right) LogicInfix
1012 \| or LogicInfix
1013 r| or (right) LogicInfix
1014 ^ exclusive or LogicInfix
1015 r^ exclusive or (right) LogicInfix
1016 < less than ComparisonInfix
1017 <= less than or equal ComparisonInfix
1018 > greater than ComparisonInfix
1019 >= greater than or equal ComparisonInfix
1020 >> right bit shift BitwiseInfix
1021 r>> right bit shift (right) BitwiseInfix
1022 << left bit shift BitwiseInfix
1023 r<< left bit shift (right) BitwiseInfix
1024 [] get item ItemInfix
1025 [] = set item ItemInfix
1026 [missing] missing item ItemInfix
1027 del [] delete item ItemInfix
1028 ~ invert UnaryInfix
1029 x- negative UnaryInfix
1030 x+ positive UnaryInfix
1031 ========= =========================== ===============
1032 '''
1033 pass