@@ -3152,35 +3152,115 @@ def test_non_frozen_normal_derived(self):
31523152 class D :
31533153 x : int
31543154 y : int = 10
3155+ z : int = 1
3156+
3157+ @property
3158+ def readonly (self ) -> int :
3159+ return self .x
3160+
3161+ @property
3162+ def prop (self ) -> int :
3163+ return self .z
3164+
3165+ @prop .setter
3166+ def prop (self , val : int ) -> None :
3167+ object .__setattr__ (self , 'z' , val )
3168+
3169+ @prop .deleter
3170+ def prop (self ) -> None :
3171+ object .__setattr__ (self , 'z' , 0 )
3172+
3173+ d = D (5 )
3174+ self .assertEqual (d .x , 5 )
3175+ self .assertEqual (d .y , 10 )
3176+ self .assertEqual (d .z , 1 )
3177+ self .assertEqual (d .readonly , 5 )
3178+ self .assertEqual (d .prop , 1 )
3179+
3180+ with self .assertRaises (FrozenInstanceError ):
3181+ d .x = 5
3182+ with self .assertRaises (FrozenInstanceError ):
3183+ d .readonly = 5
3184+ with self .assertRaises (FrozenInstanceError ):
3185+ d .z = 5
3186+ with self .assertRaises (FrozenInstanceError ):
3187+ d .prop = 5
3188+ with self .assertRaises (FrozenInstanceError ):
3189+ del d .prop
3190+
3191+ self .assertEqual (d .x , 5 )
3192+ self .assertEqual (d .y , 10 )
3193+ self .assertEqual (d .z , 1 )
3194+ self .assertEqual (d .readonly , 5 )
3195+ self .assertEqual (d .prop , 1 )
31553196
31563197 class S (D ):
31573198 pass
31583199
31593200 s = S (3 )
31603201 self .assertEqual (s .x , 3 )
31613202 self .assertEqual (s .y , 10 )
3203+ self .assertEqual (s .z , 1 )
3204+ self .assertEqual (s .readonly , 3 )
3205+ self .assertEqual (s .prop , 1 )
3206+ # Can set new attrs:
31623207 s .cached = True
3208+ self .assertTrue (s .cached )
3209+ # Can mutate them:
3210+ s .cached = False
3211+ self .assertFalse (s .cached )
3212+
3213+ # Can also change writable properties:
3214+ with self .assertRaisesRegex (
3215+ AttributeError ,
3216+ 'object has no setter' ,
3217+ ) as cm :
3218+ s .readonly = 5
3219+ self .assertNotIsInstance (cm .exception , FrozenInstanceError )
3220+ s .prop = 2
3221+ self .assertEqual (s .x , 3 )
3222+ self .assertEqual (s .readonly , 3 )
3223+ self .assertEqual (s .prop , 2 )
3224+ self .assertEqual (s .z , 2 )
31633225
31643226 # But can't change the frozen attributes.
31653227 with self .assertRaises (FrozenInstanceError ):
31663228 s .x = 5
31673229 with self .assertRaises (FrozenInstanceError ):
31683230 s .y = 5
3231+ with self .assertRaises (FrozenInstanceError ):
3232+ s .z = 5
31693233 self .assertEqual (s .x , 3 )
31703234 self .assertEqual (s .y , 10 )
3171- self .assertEqual (s .cached , True )
3235+ self .assertEqual (s .z , 2 )
3236+ self .assertIs (s .cached , False )
31723237
31733238 with self .assertRaises (FrozenInstanceError ):
31743239 del s .x
31753240 self .assertEqual (s .x , 3 )
31763241 with self .assertRaises (FrozenInstanceError ):
31773242 del s .y
31783243 self .assertEqual (s .y , 10 )
3244+ with self .assertRaisesRegex (
3245+ AttributeError ,
3246+ 'object has no deleter' ,
3247+ ) as cm :
3248+ del s .readonly
3249+ self .assertNotIsInstance (cm .exception , FrozenInstanceError )
3250+ self .assertEqual (s .x , 3 )
3251+ self .assertEqual (s .readonly , 3 )
31793252 del s .cached
31803253 self .assertFalse (hasattr (s , 'cached' ))
3181- with self .assertRaises (AttributeError ) as cm :
3254+ with self .assertRaisesRegex (
3255+ AttributeError ,
3256+ "object has no attribute 'cached'" ,
3257+ ) as cm :
31823258 del s .cached
31833259 self .assertNotIsInstance (cm .exception , FrozenInstanceError )
3260+ del s .prop
3261+ self .assertEqual (s .z , 0 )
3262+ self .assertEqual (s .prop , 0 )
3263+ del s .prop
31843264
31853265 def test_non_frozen_normal_derived_from_empty_frozen (self ):
31863266 @dataclass (frozen = True )
0 commit comments