@@ -273,6 +273,13 @@ def __set_name__(self, enum_class, member_name):
273
273
enum_member .__objclass__ = enum_class
274
274
enum_member .__init__ (* args )
275
275
enum_member ._sort_order_ = len (enum_class ._member_names_ )
276
+
277
+ if Flag is not None and issubclass (enum_class , Flag ):
278
+ enum_class ._flag_mask_ |= value
279
+ if _is_single_bit (value ):
280
+ enum_class ._singles_mask_ |= value
281
+ enum_class ._all_bits_ = 2 ** ((enum_class ._flag_mask_ ).bit_length ()) - 1
282
+
276
283
# If another member with the same value was already defined, the
277
284
# new member becomes an alias to the existing one.
278
285
try :
@@ -525,12 +532,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
525
532
classdict ['_use_args_' ] = use_args
526
533
#
527
534
# convert future enum members into temporary _proto_members
528
- # and record integer values in case this will be a Flag
529
- flag_mask = 0
530
535
for name in member_names :
531
536
value = classdict [name ]
532
- if isinstance (value , int ):
533
- flag_mask |= value
534
537
classdict [name ] = _proto_member (value )
535
538
#
536
539
# house-keeping structures
@@ -547,8 +550,9 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
547
550
boundary
548
551
or getattr (first_enum , '_boundary_' , None )
549
552
)
550
- classdict ['_flag_mask_' ] = flag_mask
551
- classdict ['_all_bits_' ] = 2 ** ((flag_mask ).bit_length ()) - 1
553
+ classdict ['_flag_mask_' ] = 0
554
+ classdict ['_singles_mask_' ] = 0
555
+ classdict ['_all_bits_' ] = 0
552
556
classdict ['_inverted_' ] = None
553
557
try :
554
558
exc = None
@@ -637,21 +641,10 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
637
641
):
638
642
delattr (enum_class , '_boundary_' )
639
643
delattr (enum_class , '_flag_mask_' )
644
+ delattr (enum_class , '_singles_mask_' )
640
645
delattr (enum_class , '_all_bits_' )
641
646
delattr (enum_class , '_inverted_' )
642
647
elif Flag is not None and issubclass (enum_class , Flag ):
643
- # ensure _all_bits_ is correct and there are no missing flags
644
- single_bit_total = 0
645
- multi_bit_total = 0
646
- for flag in enum_class ._member_map_ .values ():
647
- flag_value = flag ._value_
648
- if _is_single_bit (flag_value ):
649
- single_bit_total |= flag_value
650
- else :
651
- # multi-bit flags are considered aliases
652
- multi_bit_total |= flag_value
653
- enum_class ._flag_mask_ = single_bit_total
654
- #
655
648
# set correct __iter__
656
649
member_list = [m ._value_ for m in enum_class ]
657
650
if member_list != sorted (member_list ):
@@ -1303,8 +1296,8 @@ def _reduce_ex_by_global_name(self, proto):
1303
1296
class FlagBoundary (StrEnum ):
1304
1297
"""
1305
1298
control how out of range values are handled
1306
- "strict" -> error is raised
1307
- "conform" -> extra bits are discarded [default for Flag]
1299
+ "strict" -> error is raised [default for Flag]
1300
+ "conform" -> extra bits are discarded
1308
1301
"eject" -> lose flag status
1309
1302
"keep" -> keep flag status and all bits [default for IntFlag]
1310
1303
"""
@@ -1315,7 +1308,7 @@ class FlagBoundary(StrEnum):
1315
1308
STRICT , CONFORM , EJECT , KEEP = FlagBoundary
1316
1309
1317
1310
1318
- class Flag (Enum , boundary = CONFORM ):
1311
+ class Flag (Enum , boundary = STRICT ):
1319
1312
"""
1320
1313
Support for flags
1321
1314
"""
@@ -1393,6 +1386,7 @@ def _missing_(cls, value):
1393
1386
# - value must not include any skipped flags (e.g. if bit 2 is not
1394
1387
# defined, then 0d10 is invalid)
1395
1388
flag_mask = cls ._flag_mask_
1389
+ singles_mask = cls ._singles_mask_
1396
1390
all_bits = cls ._all_bits_
1397
1391
neg_value = None
1398
1392
if (
@@ -1424,7 +1418,8 @@ def _missing_(cls, value):
1424
1418
value = all_bits + 1 + value
1425
1419
# get members and unknown
1426
1420
unknown = value & ~ flag_mask
1427
- member_value = value & flag_mask
1421
+ aliases = value & ~ singles_mask
1422
+ member_value = value & singles_mask
1428
1423
if unknown and cls ._boundary_ is not KEEP :
1429
1424
raise ValueError (
1430
1425
'%s(%r) --> unknown values %r [%s]'
@@ -1438,11 +1433,25 @@ def _missing_(cls, value):
1438
1433
pseudo_member = cls ._member_type_ .__new__ (cls , value )
1439
1434
if not hasattr (pseudo_member , '_value_' ):
1440
1435
pseudo_member ._value_ = value
1441
- if member_value :
1442
- pseudo_member ._name_ = '|' .join ([
1443
- m ._name_ for m in cls ._iter_member_ (member_value )
1444
- ])
1445
- if unknown :
1436
+ if member_value or aliases :
1437
+ members = []
1438
+ combined_value = 0
1439
+ for m in cls ._iter_member_ (member_value ):
1440
+ members .append (m )
1441
+ combined_value |= m ._value_
1442
+ if aliases :
1443
+ value = member_value | aliases
1444
+ for n , pm in cls ._member_map_ .items ():
1445
+ if pm not in members and pm ._value_ and pm ._value_ & value == pm ._value_ :
1446
+ members .append (pm )
1447
+ combined_value |= pm ._value_
1448
+ unknown = value ^ combined_value
1449
+ pseudo_member ._name_ = '|' .join ([m ._name_ for m in members ])
1450
+ if not combined_value :
1451
+ pseudo_member ._name_ = None
1452
+ elif unknown and cls ._boundary_ is STRICT :
1453
+ raise ValueError ('%r: no members with value %r' % (cls , unknown ))
1454
+ elif unknown :
1446
1455
pseudo_member ._name_ += '|%s' % cls ._numeric_repr_ (unknown )
1447
1456
else :
1448
1457
pseudo_member ._name_ = None
@@ -1671,6 +1680,7 @@ def convert_class(cls):
1671
1680
body ['_boundary_' ] = boundary or etype ._boundary_
1672
1681
body ['_flag_mask_' ] = None
1673
1682
body ['_all_bits_' ] = None
1683
+ body ['_singles_mask_' ] = None
1674
1684
body ['_inverted_' ] = None
1675
1685
body ['__or__' ] = Flag .__or__
1676
1686
body ['__xor__' ] = Flag .__xor__
@@ -1743,7 +1753,8 @@ def convert_class(cls):
1743
1753
else :
1744
1754
multi_bits |= value
1745
1755
gnv_last_values .append (value )
1746
- enum_class ._flag_mask_ = single_bits
1756
+ enum_class ._flag_mask_ = single_bits | multi_bits
1757
+ enum_class ._singles_mask_ = single_bits
1747
1758
enum_class ._all_bits_ = 2 ** ((single_bits | multi_bits ).bit_length ()) - 1
1748
1759
# set correct __iter__
1749
1760
member_list = [m ._value_ for m in enum_class ]
0 commit comments