@@ -92,37 +92,51 @@ class DummyFraction(fractions.Fraction):
9292def _components (r ):
9393 return (r .numerator , r .denominator )
9494
95- def is_eq (a , b ):
95+ def typed_approx_eq (a , b ):
9696 return type (a ) == type (b ) and (a == b or math .isclose (a , b ))
9797
98- class One :
98+ class Symbolic :
99+ """Simple non-numeric class for testing mixed arithmetic.
100+ It is not Integral, Rational, Real or Complex, and cannot be conveted
101+ to int, float or complex. but it supports some arithmetic operations.
102+ """
103+ def __init__ (self , value ):
104+ self .value = value
99105 def __mul__ (self , other ):
100106 if isinstance (other , F ):
101107 return NotImplemented
102- return other
108+ return self . __class__ ( f' { self } * { other } ' )
103109 def __rmul__ (self , other ):
104- return other
110+ return self . __class__ ( f' { other } * { self } ' )
105111 def __truediv__ (self , other ):
106112 if isinstance (other , F ):
107113 return NotImplemented
108- return 1 / other
114+ return self . __class__ ( f' { self } / { other } ' )
109115 def __rtruediv__ (self , other ):
110- return other
116+ return self . __class__ ( f' { other } / { self } ' )
111117 def __mod__ (self , other ):
112118 if isinstance (other , F ):
113119 return NotImplemented
114- return 1 % other
120+ return self . __class__ ( f' { self } % { other } ' )
115121 def __rmod__ (self , other ):
116- return other % 1
122+ return self . __class__ ( f' { other } % { self } ' )
117123 def __pow__ (self , other ):
118124 if isinstance (other , F ):
119125 return NotImplemented
120- return self
126+ return self . __class__ ( f' { self } ** { other } ' )
121127 def __rpow__ (self , other ):
122- return other
123- One = One ()
128+ return self .__class__ (f'{ other } ** { self } ' )
129+ def __eq__ (self , other ):
130+ if other .__class__ != self .__class__ :
131+ return NotImplemented
132+ return self .value == other .value
133+ def __str__ (self ):
134+ return f'{ self .value } '
135+ def __repr__ (self ):
136+ return f'{ self .__class__ .__name__ } ({ self .value !r} )'
124137
125138class Rat :
139+ """Simple Rational class for testing mixed arithmetic."""
126140 def __init__ (self , n , d ):
127141 self .numerator = n
128142 self .denominator = d
@@ -163,13 +177,14 @@ def __float__(self):
163177 def __eq__ (self , other ):
164178 if self .__class__ != other .__class__ :
165179 return NotImplemented
166- return (is_eq (self .numerator , other .numerator ) and
167- is_eq (self .denominator , other .denominator ))
180+ return (typed_approx_eq (self .numerator , other .numerator ) and
181+ typed_approx_eq (self .denominator , other .denominator ))
168182 def __repr__ (self ):
169183 return f'{ self .__class__ .__name__ } ({ self .numerator !r} , { self .denominator !r} )'
170184numbers .Rational .register (Rat )
171185
172186class Root :
187+ """Simple Real class for testing mixed arithmetic."""
173188 def __init__ (self , v , n = F (2 )):
174189 self .base = v
175190 self .degree = n
@@ -194,12 +209,13 @@ def __float__(self):
194209 def __eq__ (self , other ):
195210 if self .__class__ != other .__class__ :
196211 return NotImplemented
197- return is_eq (self .base , other .base ) and is_eq (self .degree , other .degree )
212+ return typed_approx_eq (self .base , other .base ) and typed_approx_eq (self .degree , other .degree )
198213 def __repr__ (self ):
199214 return f'{ self .__class__ .__name__ } ({ self .base !r} , { self .degree !r} )'
200215numbers .Real .register (Root )
201216
202217class Polar :
218+ """Simple Complex class for testing mixed arithmetic."""
203219 def __init__ (self , r , phi ):
204220 self .r = r
205221 self .phi = phi
@@ -222,12 +238,13 @@ def __pow__(self, other):
222238 def __eq__ (self , other ):
223239 if self .__class__ != other .__class__ :
224240 return NotImplemented
225- return is_eq (self .r , other .r ) and is_eq (self .phi , other .phi )
241+ return typed_approx_eq (self .r , other .r ) and typed_approx_eq (self .phi , other .phi )
226242 def __repr__ (self ):
227243 return f'{ self .__class__ .__name__ } ({ self .r !r} , { self .phi !r} )'
228244numbers .Complex .register (Polar )
229245
230246class Rect :
247+ """Other simple Complex class for testing mixed arithmetic."""
231248 def __init__ (self , x , y ):
232249 self .x = x
233250 self .y = y
@@ -251,7 +268,7 @@ def __complex__(self):
251268 def __eq__ (self , other ):
252269 if self .__class__ != other .__class__ :
253270 return NotImplemented
254- return is_eq (self .x , other .x ) and is_eq (self .y , other .y )
271+ return typed_approx_eq (self .x , other .x ) and typed_approx_eq (self .y , other .y )
255272 def __repr__ (self ):
256273 return f'{ self .__class__ .__name__ } ({ self .x !r} , { self .y !r} )'
257274numbers .Complex .register (Rect )
@@ -780,8 +797,8 @@ def testMixedMultiplication(self):
780797 self .assertRaises (TypeError , operator .mul , Polar (4 , 2 ), F (3 , 2 ))
781798 self .assertTypedEquals (Rect (4 , 3 ) * F (3 , 2 ), 6.0 + 4.5j )
782799
783- self .assertTypedEquals (F (3 , 2 ) * One , F ( 3 , 2 ))
784- self .assertRaises (TypeError , operator .mul , One , F (3 , 2 ))
800+ self .assertEqual (F (3 , 2 ) * Symbolic ( 'X' ), Symbolic ( '3/2 * X' ))
801+ self .assertRaises (TypeError , operator .mul , Symbolic ( 'X' ) , F (3 , 2 ))
785802
786803 def testMixedDivision (self ):
787804 self .assertTypedEquals (F (1 , 10 ), F (1 , 10 ) / 1 )
@@ -805,8 +822,8 @@ def testMixedDivision(self):
805822 self .assertRaises (TypeError , operator .truediv , Polar (4 , 2 ), F (2 , 3 ))
806823 self .assertTypedEquals (Rect (4 , 3 ) / F (2 , 3 ), 6.0 + 4.5j )
807824
808- self .assertTypedEquals (F (3 , 2 ) / One , F ( 3 , 2 ))
809- self .assertRaises (TypeError , operator .truediv , One , F (2 , 3 ))
825+ self .assertEqual (F (3 , 2 ) / Symbolic ( 'X' ), Symbolic ( '3/2 / X' ))
826+ self .assertRaises (TypeError , operator .truediv , Symbolic ( 'X' ) , F (2 , 3 ))
810827
811828 def testMixedIntegerDivision (self ):
812829 self .assertTypedEquals (0 , F (1 , 10 ) // 1 )
@@ -844,8 +861,8 @@ def testMixedIntegerDivision(self):
844861 self .assertRaises (TypeError , operator .mod , F (3 , 2 ), Polar (4 , 2 ))
845862 self .assertRaises (TypeError , operator .mod , Rect (4 , 3 ), F (2 , 3 ))
846863
847- self .assertTypedEquals (F (3 , 2 ) % One , F ( 1 , 2 ))
848- self .assertRaises (TypeError , operator .mod , One , F (2 , 3 ))
864+ self .assertEqual (F (3 , 2 ) % Symbolic ( 'X' ), Symbolic ( '3/2 % X' ))
865+ self .assertRaises (TypeError , operator .mod , Symbolic ( 'X' ) , F (2 , 3 ))
849866
850867 def testMixedPower (self ):
851868 # ** has more interesting conversion rules.
@@ -890,8 +907,8 @@ def testMixedPower(self):
890907 self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 1 ), Polar (0.015625 , - 6 ))
891908 self .assertTypedEquals (Polar (4 , 2 ) ** F (- 3 , 2 ), Polar (0.125 , - 3.0 ))
892909
893- self .assertTypedEquals (F (3 , 2 ) ** One , 1.5 )
894- self .assertTypedEquals (One ** F (3 , 2 ), One )
910+ self .assertTypedEquals (F (3 , 2 ) ** Symbolic ( 'X' ), Symbolic ( ' 1.5 ** X' ) )
911+ self .assertTypedEquals (Symbolic ( 'X' ) ** F (3 , 2 ), Symbolic ( 'X ** 1.5' ) )
895912
896913 def testMixingWithDecimal (self ):
897914 # Decimal refuses mixed arithmetic (but not mixed comparisons)
0 commit comments