test_enum.py 166 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712
  1. import copy
  2. import enum
  3. import doctest
  4. import inspect
  5. import os
  6. import pydoc
  7. import sys
  8. import unittest
  9. import threading
  10. import typing
  11. import builtins as bltns
  12. from collections import OrderedDict
  13. from datetime import date
  14. from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
  15. from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
  16. from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum
  17. from enum import member, nonmember, _iter_bits_lsb
  18. from io import StringIO
  19. from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
  20. from test import support
  21. from test.support import ALWAYS_EQ
  22. from test.support import threading_helper
  23. from textwrap import dedent
  24. from datetime import timedelta
  25. python_version = sys.version_info[:2]
  26. def load_tests(loader, tests, ignore):
  27. tests.addTests(doctest.DocTestSuite(enum))
  28. if os.path.exists('Doc/library/enum.rst'):
  29. tests.addTests(doctest.DocFileSuite(
  30. '../../Doc/library/enum.rst',
  31. optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
  32. ))
  33. return tests
  34. MODULE = __name__
  35. SHORT_MODULE = MODULE.split('.')[-1]
  36. # for pickle tests
  37. try:
  38. class Stooges(Enum):
  39. LARRY = 1
  40. CURLY = 2
  41. MOE = 3
  42. except Exception as exc:
  43. Stooges = exc
  44. try:
  45. class IntStooges(int, Enum):
  46. LARRY = 1
  47. CURLY = 2
  48. MOE = 3
  49. except Exception as exc:
  50. IntStooges = exc
  51. try:
  52. class FloatStooges(float, Enum):
  53. LARRY = 1.39
  54. CURLY = 2.72
  55. MOE = 3.142596
  56. except Exception as exc:
  57. FloatStooges = exc
  58. try:
  59. class FlagStooges(Flag):
  60. LARRY = 1
  61. CURLY = 2
  62. MOE = 4
  63. except Exception as exc:
  64. FlagStooges = exc
  65. class FlagStoogesWithZero(Flag):
  66. NOFLAG = 0
  67. LARRY = 1
  68. CURLY = 2
  69. MOE = 4
  70. class IntFlagStooges(IntFlag):
  71. LARRY = 1
  72. CURLY = 2
  73. MOE = 4
  74. class IntFlagStoogesWithZero(IntFlag):
  75. NOFLAG = 0
  76. LARRY = 1
  77. CURLY = 2
  78. MOE = 4
  79. # for pickle test and subclass tests
  80. class Name(StrEnum):
  81. BDFL = 'Guido van Rossum'
  82. FLUFL = 'Barry Warsaw'
  83. try:
  84. Question = Enum('Question', 'who what when where why', module=__name__)
  85. except Exception as exc:
  86. Question = exc
  87. try:
  88. Answer = Enum('Answer', 'him this then there because')
  89. except Exception as exc:
  90. Answer = exc
  91. try:
  92. Theory = Enum('Theory', 'rule law supposition', qualname='spanish_inquisition')
  93. except Exception as exc:
  94. Theory = exc
  95. # for doctests
  96. try:
  97. class Fruit(Enum):
  98. TOMATO = 1
  99. BANANA = 2
  100. CHERRY = 3
  101. except Exception:
  102. pass
  103. def test_pickle_dump_load(assertion, source, target=None):
  104. if target is None:
  105. target = source
  106. for protocol in range(HIGHEST_PROTOCOL + 1):
  107. assertion(loads(dumps(source, protocol=protocol)), target)
  108. def test_pickle_exception(assertion, exception, obj):
  109. for protocol in range(HIGHEST_PROTOCOL + 1):
  110. with assertion(exception):
  111. dumps(obj, protocol=protocol)
  112. class TestHelpers(unittest.TestCase):
  113. # _is_descriptor, _is_sunder, _is_dunder
  114. sunder_names = '_bad_', '_good_', '_what_ho_'
  115. dunder_names = '__mal__', '__bien__', '__que_que__'
  116. private_names = '_MyEnum__private', '_MyEnum__still_private'
  117. private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
  118. random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
  119. def test_is_descriptor(self):
  120. class foo:
  121. pass
  122. for attr in ('__get__','__set__','__delete__'):
  123. obj = foo()
  124. self.assertFalse(enum._is_descriptor(obj))
  125. setattr(obj, attr, 1)
  126. self.assertTrue(enum._is_descriptor(obj))
  127. def test_sunder(self):
  128. for name in self.sunder_names + self.private_and_sunder_names:
  129. self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
  130. for name in self.dunder_names + self.private_names + self.random_names:
  131. self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
  132. for s in ('_a_', '_aa_'):
  133. self.assertTrue(enum._is_sunder(s))
  134. for s in ('a', 'a_', '_a', '__a', 'a__', '__a__', '_a__', '__a_', '_',
  135. '__', '___', '____', '_____',):
  136. self.assertFalse(enum._is_sunder(s))
  137. def test_dunder(self):
  138. for name in self.dunder_names:
  139. self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
  140. for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
  141. self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
  142. for s in ('__a__', '__aa__'):
  143. self.assertTrue(enum._is_dunder(s))
  144. for s in ('a', 'a_', '_a', '__a', 'a__', '_a_', '_a__', '__a_', '_',
  145. '__', '___', '____', '_____',):
  146. self.assertFalse(enum._is_dunder(s))
  147. def test_is_private(self):
  148. for name in self.private_names + self.private_and_sunder_names:
  149. self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
  150. for name in self.sunder_names + self.dunder_names + self.random_names:
  151. self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
  152. def test_iter_bits_lsb(self):
  153. self.assertEqual(list(_iter_bits_lsb(7)), [1, 2, 4])
  154. self.assertRaisesRegex(ValueError, '-8 is not a positive integer', list, _iter_bits_lsb(-8))
  155. # for subclassing tests
  156. class classproperty:
  157. def __init__(self, fget=None, fset=None, fdel=None, doc=None):
  158. self.fget = fget
  159. self.fset = fset
  160. self.fdel = fdel
  161. if doc is None and fget is not None:
  162. doc = fget.__doc__
  163. self.__doc__ = doc
  164. def __get__(self, instance, ownerclass):
  165. return self.fget(ownerclass)
  166. # for global repr tests
  167. @enum.global_enum
  168. class HeadlightsK(IntFlag, boundary=enum.KEEP):
  169. OFF_K = 0
  170. LOW_BEAM_K = auto()
  171. HIGH_BEAM_K = auto()
  172. FOG_K = auto()
  173. @enum.global_enum
  174. class HeadlightsC(IntFlag, boundary=enum.CONFORM):
  175. OFF_C = 0
  176. LOW_BEAM_C = auto()
  177. HIGH_BEAM_C = auto()
  178. FOG_C = auto()
  179. @enum.global_enum
  180. class NoName(Flag):
  181. ONE = 1
  182. TWO = 2
  183. # tests
  184. class _EnumTests:
  185. """
  186. Test for behavior that is the same across the different types of enumerations.
  187. """
  188. values = None
  189. def setUp(self):
  190. class BaseEnum(self.enum_type):
  191. @enum.property
  192. def first(self):
  193. return '%s is first!' % self.name
  194. class MainEnum(BaseEnum):
  195. first = auto()
  196. second = auto()
  197. third = auto()
  198. if issubclass(self.enum_type, Flag):
  199. dupe = 3
  200. else:
  201. dupe = third
  202. self.MainEnum = MainEnum
  203. #
  204. class NewStrEnum(self.enum_type):
  205. def __str__(self):
  206. return self.name.upper()
  207. first = auto()
  208. self.NewStrEnum = NewStrEnum
  209. #
  210. class NewFormatEnum(self.enum_type):
  211. def __format__(self, spec):
  212. return self.name.upper()
  213. first = auto()
  214. self.NewFormatEnum = NewFormatEnum
  215. #
  216. class NewStrFormatEnum(self.enum_type):
  217. def __str__(self):
  218. return self.name.title()
  219. def __format__(self, spec):
  220. return ''.join(reversed(self.name))
  221. first = auto()
  222. self.NewStrFormatEnum = NewStrFormatEnum
  223. #
  224. class NewBaseEnum(self.enum_type):
  225. def __str__(self):
  226. return self.name.title()
  227. def __format__(self, spec):
  228. return ''.join(reversed(self.name))
  229. class NewSubEnum(NewBaseEnum):
  230. first = auto()
  231. self.NewSubEnum = NewSubEnum
  232. #
  233. self.is_flag = False
  234. self.names = ['first', 'second', 'third']
  235. if issubclass(MainEnum, StrEnum):
  236. self.values = self.names
  237. elif MainEnum._member_type_ is str:
  238. self.values = ['1', '2', '3']
  239. elif issubclass(self.enum_type, Flag):
  240. self.values = [1, 2, 4]
  241. self.is_flag = True
  242. self.dupe2 = MainEnum(5)
  243. else:
  244. self.values = self.values or [1, 2, 3]
  245. #
  246. if not getattr(self, 'source_values', False):
  247. self.source_values = self.values
  248. def assertFormatIsValue(self, spec, member):
  249. self.assertEqual(spec.format(member), spec.format(member.value))
  250. def assertFormatIsStr(self, spec, member):
  251. self.assertEqual(spec.format(member), spec.format(str(member)))
  252. def test_attribute_deletion(self):
  253. class Season(self.enum_type):
  254. SPRING = auto()
  255. SUMMER = auto()
  256. AUTUMN = auto()
  257. #
  258. def spam(cls):
  259. pass
  260. #
  261. self.assertTrue(hasattr(Season, 'spam'))
  262. del Season.spam
  263. self.assertFalse(hasattr(Season, 'spam'))
  264. #
  265. with self.assertRaises(AttributeError):
  266. del Season.SPRING
  267. with self.assertRaises(AttributeError):
  268. del Season.DRY
  269. with self.assertRaises(AttributeError):
  270. del Season.SPRING.name
  271. def test_basics(self):
  272. TE = self.MainEnum
  273. if self.is_flag:
  274. self.assertEqual(repr(TE), "<flag 'MainEnum'>")
  275. self.assertEqual(str(TE), "<flag 'MainEnum'>")
  276. self.assertEqual(format(TE), "<flag 'MainEnum'>")
  277. self.assertTrue(TE(5) is self.dupe2)
  278. else:
  279. self.assertEqual(repr(TE), "<enum 'MainEnum'>")
  280. self.assertEqual(str(TE), "<enum 'MainEnum'>")
  281. self.assertEqual(format(TE), "<enum 'MainEnum'>")
  282. self.assertEqual(list(TE), [TE.first, TE.second, TE.third])
  283. self.assertEqual(
  284. [m.name for m in TE],
  285. self.names,
  286. )
  287. self.assertEqual(
  288. [m.value for m in TE],
  289. self.values,
  290. )
  291. self.assertEqual(
  292. [m.first for m in TE],
  293. ['first is first!', 'second is first!', 'third is first!']
  294. )
  295. for member, name in zip(TE, self.names, strict=True):
  296. self.assertIs(TE[name], member)
  297. for member, value in zip(TE, self.values, strict=True):
  298. self.assertIs(TE(value), member)
  299. if issubclass(TE, StrEnum):
  300. self.assertTrue(TE.dupe is TE('third') is TE['dupe'])
  301. elif TE._member_type_ is str:
  302. self.assertTrue(TE.dupe is TE('3') is TE['dupe'])
  303. elif issubclass(TE, Flag):
  304. self.assertTrue(TE.dupe is TE(3) is TE['dupe'])
  305. else:
  306. self.assertTrue(TE.dupe is TE(self.values[2]) is TE['dupe'])
  307. def test_bool_is_true(self):
  308. class Empty(self.enum_type):
  309. pass
  310. self.assertTrue(Empty)
  311. #
  312. self.assertTrue(self.MainEnum)
  313. for member in self.MainEnum:
  314. self.assertTrue(member)
  315. def test_changing_member_fails(self):
  316. MainEnum = self.MainEnum
  317. with self.assertRaises(AttributeError):
  318. self.MainEnum.second = 'really first'
  319. @unittest.skipIf(
  320. python_version >= (3, 12),
  321. '__contains__ now returns True/False for all inputs',
  322. )
  323. def test_contains_er(self):
  324. MainEnum = self.MainEnum
  325. self.assertIn(MainEnum.third, MainEnum)
  326. with self.assertRaises(TypeError):
  327. with self.assertWarns(DeprecationWarning):
  328. self.source_values[1] in MainEnum
  329. with self.assertRaises(TypeError):
  330. with self.assertWarns(DeprecationWarning):
  331. 'first' in MainEnum
  332. val = MainEnum.dupe
  333. self.assertIn(val, MainEnum)
  334. #
  335. class OtherEnum(Enum):
  336. one = auto()
  337. two = auto()
  338. self.assertNotIn(OtherEnum.two, MainEnum)
  339. @unittest.skipIf(
  340. python_version < (3, 12),
  341. '__contains__ works only with enum memmbers before 3.12',
  342. )
  343. def test_contains_tf(self):
  344. MainEnum = self.MainEnum
  345. self.assertIn(MainEnum.first, MainEnum)
  346. self.assertTrue(self.source_values[0] in MainEnum)
  347. self.assertFalse('first' in MainEnum)
  348. val = MainEnum.dupe
  349. self.assertIn(val, MainEnum)
  350. #
  351. class OtherEnum(Enum):
  352. one = auto()
  353. two = auto()
  354. self.assertNotIn(OtherEnum.two, MainEnum)
  355. def test_dir_on_class(self):
  356. TE = self.MainEnum
  357. self.assertEqual(set(dir(TE)), set(enum_dir(TE)))
  358. def test_dir_on_item(self):
  359. TE = self.MainEnum
  360. self.assertEqual(set(dir(TE.first)), set(member_dir(TE.first)))
  361. def test_dir_with_added_behavior(self):
  362. class Test(self.enum_type):
  363. this = auto()
  364. these = auto()
  365. def wowser(self):
  366. return ("Wowser! I'm %s!" % self.name)
  367. self.assertTrue('wowser' not in dir(Test))
  368. self.assertTrue('wowser' in dir(Test.this))
  369. def test_dir_on_sub_with_behavior_on_super(self):
  370. # see issue22506
  371. class SuperEnum(self.enum_type):
  372. def invisible(self):
  373. return "did you see me?"
  374. class SubEnum(SuperEnum):
  375. sample = auto()
  376. self.assertTrue('invisible' not in dir(SubEnum))
  377. self.assertTrue('invisible' in dir(SubEnum.sample))
  378. def test_dir_on_sub_with_behavior_including_instance_dict_on_super(self):
  379. # see issue40084
  380. class SuperEnum(self.enum_type):
  381. def __new__(cls, *value, **kwds):
  382. new = self.enum_type._member_type_.__new__
  383. if self.enum_type._member_type_ is object:
  384. obj = new(cls)
  385. else:
  386. if isinstance(value[0], tuple):
  387. create_value ,= value[0]
  388. else:
  389. create_value = value
  390. obj = new(cls, *create_value)
  391. obj._value_ = value[0] if len(value) == 1 else value
  392. obj.description = 'test description'
  393. return obj
  394. class SubEnum(SuperEnum):
  395. sample = self.source_values[1]
  396. self.assertTrue('description' not in dir(SubEnum))
  397. self.assertTrue('description' in dir(SubEnum.sample), dir(SubEnum.sample))
  398. def test_enum_in_enum_out(self):
  399. Main = self.MainEnum
  400. self.assertIs(Main(Main.first), Main.first)
  401. def test_hash(self):
  402. MainEnum = self.MainEnum
  403. mapping = {}
  404. mapping[MainEnum.first] = '1225'
  405. mapping[MainEnum.second] = '0315'
  406. mapping[MainEnum.third] = '0704'
  407. self.assertEqual(mapping[MainEnum.second], '0315')
  408. def test_invalid_names(self):
  409. with self.assertRaises(ValueError):
  410. class Wrong(self.enum_type):
  411. mro = 9
  412. with self.assertRaises(ValueError):
  413. class Wrong(self.enum_type):
  414. _create_= 11
  415. with self.assertRaises(ValueError):
  416. class Wrong(self.enum_type):
  417. _get_mixins_ = 9
  418. with self.assertRaises(ValueError):
  419. class Wrong(self.enum_type):
  420. _find_new_ = 1
  421. with self.assertRaises(ValueError):
  422. class Wrong(self.enum_type):
  423. _any_name_ = 9
  424. def test_object_str_override(self):
  425. "check that setting __str__ to object's is not reset to Enum's"
  426. class Generic(self.enum_type):
  427. item = self.source_values[2]
  428. def __repr__(self):
  429. return "%s.test" % (self._name_, )
  430. __str__ = object.__str__
  431. self.assertEqual(str(Generic.item), 'item.test')
  432. def test_overridden_str(self):
  433. NS = self.NewStrEnum
  434. self.assertEqual(str(NS.first), NS.first.name.upper())
  435. self.assertEqual(format(NS.first), NS.first.name.upper())
  436. def test_overridden_str_format(self):
  437. NSF = self.NewStrFormatEnum
  438. self.assertEqual(str(NSF.first), NSF.first.name.title())
  439. self.assertEqual(format(NSF.first), ''.join(reversed(NSF.first.name)))
  440. def test_overridden_str_format_inherited(self):
  441. NSE = self.NewSubEnum
  442. self.assertEqual(str(NSE.first), NSE.first.name.title())
  443. self.assertEqual(format(NSE.first), ''.join(reversed(NSE.first.name)))
  444. def test_programmatic_function_string(self):
  445. MinorEnum = self.enum_type('MinorEnum', 'june july august')
  446. lst = list(MinorEnum)
  447. self.assertEqual(len(lst), len(MinorEnum))
  448. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  449. self.assertEqual(
  450. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  451. lst,
  452. )
  453. values = self.values
  454. if self.enum_type is StrEnum:
  455. values = ['june','july','august']
  456. for month, av in zip('june july august'.split(), values):
  457. e = MinorEnum[month]
  458. self.assertEqual(e.value, av, list(MinorEnum))
  459. self.assertEqual(e.name, month)
  460. if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
  461. self.assertEqual(e, av)
  462. else:
  463. self.assertNotEqual(e, av)
  464. self.assertIn(e, MinorEnum)
  465. self.assertIs(type(e), MinorEnum)
  466. self.assertIs(e, MinorEnum(av))
  467. def test_programmatic_function_string_list(self):
  468. MinorEnum = self.enum_type('MinorEnum', ['june', 'july', 'august'])
  469. lst = list(MinorEnum)
  470. self.assertEqual(len(lst), len(MinorEnum))
  471. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  472. self.assertEqual(
  473. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  474. lst,
  475. )
  476. values = self.values
  477. if self.enum_type is StrEnum:
  478. values = ['june','july','august']
  479. for month, av in zip('june july august'.split(), values):
  480. e = MinorEnum[month]
  481. self.assertEqual(e.value, av)
  482. self.assertEqual(e.name, month)
  483. if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
  484. self.assertEqual(e, av)
  485. else:
  486. self.assertNotEqual(e, av)
  487. self.assertIn(e, MinorEnum)
  488. self.assertIs(type(e), MinorEnum)
  489. self.assertIs(e, MinorEnum(av))
  490. def test_programmatic_function_iterable(self):
  491. MinorEnum = self.enum_type(
  492. 'MinorEnum',
  493. (('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2]))
  494. )
  495. lst = list(MinorEnum)
  496. self.assertEqual(len(lst), len(MinorEnum))
  497. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  498. self.assertEqual(
  499. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  500. lst,
  501. )
  502. for month, av in zip('june july august'.split(), self.values):
  503. e = MinorEnum[month]
  504. self.assertEqual(e.value, av)
  505. self.assertEqual(e.name, month)
  506. if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
  507. self.assertEqual(e, av)
  508. else:
  509. self.assertNotEqual(e, av)
  510. self.assertIn(e, MinorEnum)
  511. self.assertIs(type(e), MinorEnum)
  512. self.assertIs(e, MinorEnum(av))
  513. def test_programmatic_function_from_dict(self):
  514. MinorEnum = self.enum_type(
  515. 'MinorEnum',
  516. OrderedDict((('june', self.source_values[0]), ('july', self.source_values[1]), ('august', self.source_values[2])))
  517. )
  518. lst = list(MinorEnum)
  519. self.assertEqual(len(lst), len(MinorEnum))
  520. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  521. self.assertEqual(
  522. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  523. lst,
  524. )
  525. for month, av in zip('june july august'.split(), self.values):
  526. e = MinorEnum[month]
  527. if MinorEnum._member_type_ is not object and issubclass(MinorEnum, MinorEnum._member_type_):
  528. self.assertEqual(e, av)
  529. else:
  530. self.assertNotEqual(e, av)
  531. self.assertIn(e, MinorEnum)
  532. self.assertIs(type(e), MinorEnum)
  533. self.assertIs(e, MinorEnum(av))
  534. def test_repr(self):
  535. TE = self.MainEnum
  536. if self.is_flag:
  537. self.assertEqual(repr(TE(0)), "<MainEnum: 0>")
  538. self.assertEqual(repr(TE.dupe), "<MainEnum.dupe: 3>")
  539. self.assertEqual(repr(self.dupe2), "<MainEnum.first|third: 5>")
  540. elif issubclass(TE, StrEnum):
  541. self.assertEqual(repr(TE.dupe), "<MainEnum.third: 'third'>")
  542. else:
  543. self.assertEqual(repr(TE.dupe), "<MainEnum.third: %r>" % (self.values[2], ), TE._value_repr_)
  544. for name, value, member in zip(self.names, self.values, TE, strict=True):
  545. self.assertEqual(repr(member), "<MainEnum.%s: %r>" % (member.name, member.value))
  546. def test_repr_override(self):
  547. class Generic(self.enum_type):
  548. first = auto()
  549. second = auto()
  550. third = auto()
  551. def __repr__(self):
  552. return "don't you just love shades of %s?" % self.name
  553. self.assertEqual(
  554. repr(Generic.third),
  555. "don't you just love shades of third?",
  556. )
  557. def test_inherited_repr(self):
  558. class MyEnum(self.enum_type):
  559. def __repr__(self):
  560. return "My name is %s." % self.name
  561. class MySubEnum(MyEnum):
  562. this = auto()
  563. that = auto()
  564. theother = auto()
  565. self.assertEqual(repr(MySubEnum.that), "My name is that.")
  566. def test_reversed_iteration_order(self):
  567. self.assertEqual(
  568. list(reversed(self.MainEnum)),
  569. [self.MainEnum.third, self.MainEnum.second, self.MainEnum.first],
  570. )
  571. class _PlainOutputTests:
  572. def test_str(self):
  573. TE = self.MainEnum
  574. if self.is_flag:
  575. self.assertEqual(str(TE(0)), "MainEnum(0)")
  576. self.assertEqual(str(TE.dupe), "MainEnum.dupe")
  577. self.assertEqual(str(self.dupe2), "MainEnum.first|third")
  578. else:
  579. self.assertEqual(str(TE.dupe), "MainEnum.third")
  580. for name, value, member in zip(self.names, self.values, TE, strict=True):
  581. self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
  582. def test_format(self):
  583. TE = self.MainEnum
  584. if self.is_flag:
  585. self.assertEqual(format(TE.dupe), "MainEnum.dupe")
  586. self.assertEqual(format(self.dupe2), "MainEnum.first|third")
  587. else:
  588. self.assertEqual(format(TE.dupe), "MainEnum.third")
  589. for name, value, member in zip(self.names, self.values, TE, strict=True):
  590. self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
  591. def test_overridden_format(self):
  592. NF = self.NewFormatEnum
  593. self.assertEqual(str(NF.first), "NewFormatEnum.first", '%s %r' % (NF.__str__, NF.first))
  594. self.assertEqual(format(NF.first), "FIRST")
  595. def test_format_specs(self):
  596. TE = self.MainEnum
  597. self.assertFormatIsStr('{}', TE.second)
  598. self.assertFormatIsStr('{:}', TE.second)
  599. self.assertFormatIsStr('{:20}', TE.second)
  600. self.assertFormatIsStr('{:^20}', TE.second)
  601. self.assertFormatIsStr('{:>20}', TE.second)
  602. self.assertFormatIsStr('{:<20}', TE.second)
  603. self.assertFormatIsStr('{:5.2}', TE.second)
  604. class _MixedOutputTests:
  605. def test_str(self):
  606. TE = self.MainEnum
  607. if self.is_flag:
  608. self.assertEqual(str(TE.dupe), "MainEnum.dupe")
  609. self.assertEqual(str(self.dupe2), "MainEnum.first|third")
  610. else:
  611. self.assertEqual(str(TE.dupe), "MainEnum.third")
  612. for name, value, member in zip(self.names, self.values, TE, strict=True):
  613. self.assertEqual(str(member), "MainEnum.%s" % (member.name, ))
  614. def test_format(self):
  615. TE = self.MainEnum
  616. if self.is_flag:
  617. self.assertEqual(format(TE.dupe), "MainEnum.dupe")
  618. self.assertEqual(format(self.dupe2), "MainEnum.first|third")
  619. else:
  620. self.assertEqual(format(TE.dupe), "MainEnum.third")
  621. for name, value, member in zip(self.names, self.values, TE, strict=True):
  622. self.assertEqual(format(member), "MainEnum.%s" % (member.name, ))
  623. def test_overridden_format(self):
  624. NF = self.NewFormatEnum
  625. self.assertEqual(str(NF.first), "NewFormatEnum.first")
  626. self.assertEqual(format(NF.first), "FIRST")
  627. def test_format_specs(self):
  628. TE = self.MainEnum
  629. self.assertFormatIsStr('{}', TE.first)
  630. self.assertFormatIsStr('{:}', TE.first)
  631. self.assertFormatIsStr('{:20}', TE.first)
  632. self.assertFormatIsStr('{:^20}', TE.first)
  633. self.assertFormatIsStr('{:>20}', TE.first)
  634. self.assertFormatIsStr('{:<20}', TE.first)
  635. self.assertFormatIsStr('{:5.2}', TE.first)
  636. class _MinimalOutputTests:
  637. def test_str(self):
  638. TE = self.MainEnum
  639. if self.is_flag:
  640. self.assertEqual(str(TE.dupe), "3")
  641. self.assertEqual(str(self.dupe2), "5")
  642. else:
  643. self.assertEqual(str(TE.dupe), str(self.values[2]))
  644. for name, value, member in zip(self.names, self.values, TE, strict=True):
  645. self.assertEqual(str(member), str(value))
  646. def test_format(self):
  647. TE = self.MainEnum
  648. if self.is_flag:
  649. self.assertEqual(format(TE.dupe), "3")
  650. self.assertEqual(format(self.dupe2), "5")
  651. else:
  652. self.assertEqual(format(TE.dupe), format(self.values[2]))
  653. for name, value, member in zip(self.names, self.values, TE, strict=True):
  654. self.assertEqual(format(member), format(value))
  655. def test_overridden_format(self):
  656. NF = self.NewFormatEnum
  657. self.assertEqual(str(NF.first), str(self.values[0]))
  658. self.assertEqual(format(NF.first), "FIRST")
  659. def test_format_specs(self):
  660. TE = self.MainEnum
  661. self.assertFormatIsValue('{}', TE.third)
  662. self.assertFormatIsValue('{:}', TE.third)
  663. self.assertFormatIsValue('{:20}', TE.third)
  664. self.assertFormatIsValue('{:^20}', TE.third)
  665. self.assertFormatIsValue('{:>20}', TE.third)
  666. self.assertFormatIsValue('{:<20}', TE.third)
  667. if TE._member_type_ is float:
  668. self.assertFormatIsValue('{:n}', TE.third)
  669. self.assertFormatIsValue('{:5.2}', TE.third)
  670. self.assertFormatIsValue('{:f}', TE.third)
  671. def test_copy(self):
  672. TE = self.MainEnum
  673. copied = copy.copy(TE)
  674. self.assertEqual(copied, TE)
  675. deep = copy.deepcopy(TE)
  676. self.assertEqual(deep, TE)
  677. class _FlagTests:
  678. def test_default_missing_with_wrong_type_value(self):
  679. with self.assertRaisesRegex(
  680. ValueError,
  681. "'RED' is not a valid ",
  682. ) as ctx:
  683. self.MainEnum('RED')
  684. self.assertIs(ctx.exception.__context__, None)
  685. class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase):
  686. enum_type = Enum
  687. class TestPlainFlag(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase):
  688. enum_type = Flag
  689. class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
  690. enum_type = IntEnum
  691. class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
  692. enum_type = StrEnum
  693. class TestIntFlag(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase):
  694. enum_type = IntFlag
  695. class TestMixedInt(_EnumTests, _MixedOutputTests, unittest.TestCase):
  696. class enum_type(int, Enum): pass
  697. class TestMixedStr(_EnumTests, _MixedOutputTests, unittest.TestCase):
  698. class enum_type(str, Enum): pass
  699. class TestMixedIntFlag(_EnumTests, _MixedOutputTests, _FlagTests, unittest.TestCase):
  700. class enum_type(int, Flag): pass
  701. class TestMixedDate(_EnumTests, _MixedOutputTests, unittest.TestCase):
  702. values = [date(2021, 12, 25), date(2020, 3, 15), date(2019, 11, 27)]
  703. source_values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
  704. class enum_type(date, Enum):
  705. def _generate_next_value_(name, start, count, last_values):
  706. values = [(2021, 12, 25), (2020, 3, 15), (2019, 11, 27)]
  707. return values[count]
  708. class TestMinimalDate(_EnumTests, _MinimalOutputTests, unittest.TestCase):
  709. values = [date(2023, 12, 1), date(2016, 2, 29), date(2009, 1, 1)]
  710. source_values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
  711. class enum_type(date, ReprEnum):
  712. def _generate_next_value_(name, start, count, last_values):
  713. values = [(2023, 12, 1), (2016, 2, 29), (2009, 1, 1)]
  714. return values[count]
  715. class TestMixedFloat(_EnumTests, _MixedOutputTests, unittest.TestCase):
  716. values = [1.1, 2.2, 3.3]
  717. class enum_type(float, Enum):
  718. def _generate_next_value_(name, start, count, last_values):
  719. values = [1.1, 2.2, 3.3]
  720. return values[count]
  721. class TestMinimalFloat(_EnumTests, _MinimalOutputTests, unittest.TestCase):
  722. values = [4.4, 5.5, 6.6]
  723. class enum_type(float, ReprEnum):
  724. def _generate_next_value_(name, start, count, last_values):
  725. values = [4.4, 5.5, 6.6]
  726. return values[count]
  727. class TestSpecial(unittest.TestCase):
  728. """
  729. various operations that are not attributable to every possible enum
  730. """
  731. def setUp(self):
  732. class Season(Enum):
  733. SPRING = 1
  734. SUMMER = 2
  735. AUTUMN = 3
  736. WINTER = 4
  737. self.Season = Season
  738. #
  739. class Grades(IntEnum):
  740. A = 5
  741. B = 4
  742. C = 3
  743. D = 2
  744. F = 0
  745. self.Grades = Grades
  746. #
  747. class Directional(str, Enum):
  748. EAST = 'east'
  749. WEST = 'west'
  750. NORTH = 'north'
  751. SOUTH = 'south'
  752. self.Directional = Directional
  753. #
  754. from datetime import date
  755. class Holiday(date, Enum):
  756. NEW_YEAR = 2013, 1, 1
  757. IDES_OF_MARCH = 2013, 3, 15
  758. self.Holiday = Holiday
  759. def test_bool(self):
  760. # plain Enum members are always True
  761. class Logic(Enum):
  762. true = True
  763. false = False
  764. self.assertTrue(Logic.true)
  765. self.assertTrue(Logic.false)
  766. # unless overridden
  767. class RealLogic(Enum):
  768. true = True
  769. false = False
  770. def __bool__(self):
  771. return bool(self._value_)
  772. self.assertTrue(RealLogic.true)
  773. self.assertFalse(RealLogic.false)
  774. # mixed Enums depend on mixed-in type
  775. class IntLogic(int, Enum):
  776. true = 1
  777. false = 0
  778. self.assertTrue(IntLogic.true)
  779. self.assertFalse(IntLogic.false)
  780. def test_comparisons(self):
  781. Season = self.Season
  782. with self.assertRaises(TypeError):
  783. Season.SPRING < Season.WINTER
  784. with self.assertRaises(TypeError):
  785. Season.SPRING > 4
  786. #
  787. self.assertNotEqual(Season.SPRING, 1)
  788. #
  789. class Part(Enum):
  790. SPRING = 1
  791. CLIP = 2
  792. BARREL = 3
  793. #
  794. self.assertNotEqual(Season.SPRING, Part.SPRING)
  795. with self.assertRaises(TypeError):
  796. Season.SPRING < Part.CLIP
  797. @unittest.skip('to-do list')
  798. def test_dir_with_custom_dunders(self):
  799. class PlainEnum(Enum):
  800. pass
  801. cls_dir = dir(PlainEnum)
  802. self.assertNotIn('__repr__', cls_dir)
  803. self.assertNotIn('__str__', cls_dir)
  804. self.assertNotIn('__format__', cls_dir)
  805. self.assertNotIn('__init__', cls_dir)
  806. #
  807. class MyEnum(Enum):
  808. def __repr__(self):
  809. return object.__repr__(self)
  810. def __str__(self):
  811. return object.__repr__(self)
  812. def __format__(self):
  813. return object.__repr__(self)
  814. def __init__(self):
  815. pass
  816. cls_dir = dir(MyEnum)
  817. self.assertIn('__repr__', cls_dir)
  818. self.assertIn('__str__', cls_dir)
  819. self.assertIn('__format__', cls_dir)
  820. self.assertIn('__init__', cls_dir)
  821. def test_duplicate_name_error(self):
  822. with self.assertRaises(TypeError):
  823. class Color(Enum):
  824. red = 1
  825. green = 2
  826. blue = 3
  827. red = 4
  828. #
  829. with self.assertRaises(TypeError):
  830. class Color(Enum):
  831. red = 1
  832. green = 2
  833. blue = 3
  834. def red(self):
  835. return 'red'
  836. #
  837. with self.assertRaises(TypeError):
  838. class Color(Enum):
  839. @enum.property
  840. def red(self):
  841. return 'redder'
  842. red = 1
  843. green = 2
  844. blue = 3
  845. def test_enum_function_with_qualname(self):
  846. if isinstance(Theory, Exception):
  847. raise Theory
  848. self.assertEqual(Theory.__qualname__, 'spanish_inquisition')
  849. def test_enum_of_types(self):
  850. """Support using Enum to refer to types deliberately."""
  851. class MyTypes(Enum):
  852. i = int
  853. f = float
  854. s = str
  855. self.assertEqual(MyTypes.i.value, int)
  856. self.assertEqual(MyTypes.f.value, float)
  857. self.assertEqual(MyTypes.s.value, str)
  858. class Foo:
  859. pass
  860. class Bar:
  861. pass
  862. class MyTypes2(Enum):
  863. a = Foo
  864. b = Bar
  865. self.assertEqual(MyTypes2.a.value, Foo)
  866. self.assertEqual(MyTypes2.b.value, Bar)
  867. class SpamEnumNotInner:
  868. pass
  869. class SpamEnum(Enum):
  870. spam = SpamEnumNotInner
  871. self.assertEqual(SpamEnum.spam.value, SpamEnumNotInner)
  872. def test_enum_of_generic_aliases(self):
  873. class E(Enum):
  874. a = typing.List[int]
  875. b = list[int]
  876. self.assertEqual(E.a.value, typing.List[int])
  877. self.assertEqual(E.b.value, list[int])
  878. self.assertEqual(repr(E.a), '<E.a: typing.List[int]>')
  879. self.assertEqual(repr(E.b), '<E.b: list[int]>')
  880. @unittest.skipIf(
  881. python_version >= (3, 13),
  882. 'inner classes are not members',
  883. )
  884. def test_nested_classes_in_enum_are_members(self):
  885. """
  886. Check for warnings pre-3.13
  887. """
  888. with self.assertWarnsRegex(DeprecationWarning, 'will not become a member'):
  889. class Outer(Enum):
  890. a = 1
  891. b = 2
  892. class Inner(Enum):
  893. foo = 10
  894. bar = 11
  895. self.assertTrue(isinstance(Outer.Inner, Outer))
  896. self.assertEqual(Outer.a.value, 1)
  897. self.assertEqual(Outer.Inner.value.foo.value, 10)
  898. self.assertEqual(
  899. list(Outer.Inner.value),
  900. [Outer.Inner.value.foo, Outer.Inner.value.bar],
  901. )
  902. self.assertEqual(
  903. list(Outer),
  904. [Outer.a, Outer.b, Outer.Inner],
  905. )
  906. @unittest.skipIf(
  907. python_version < (3, 13),
  908. 'inner classes are still members',
  909. )
  910. def test_nested_classes_in_enum_are_not_members(self):
  911. """Support locally-defined nested classes."""
  912. class Outer(Enum):
  913. a = 1
  914. b = 2
  915. class Inner(Enum):
  916. foo = 10
  917. bar = 11
  918. self.assertTrue(isinstance(Outer.Inner, type))
  919. self.assertEqual(Outer.a.value, 1)
  920. self.assertEqual(Outer.Inner.foo.value, 10)
  921. self.assertEqual(
  922. list(Outer.Inner),
  923. [Outer.Inner.foo, Outer.Inner.bar],
  924. )
  925. self.assertEqual(
  926. list(Outer),
  927. [Outer.a, Outer.b],
  928. )
  929. def test_nested_classes_in_enum_with_nonmember(self):
  930. class Outer(Enum):
  931. a = 1
  932. b = 2
  933. @nonmember
  934. class Inner(Enum):
  935. foo = 10
  936. bar = 11
  937. self.assertTrue(isinstance(Outer.Inner, type))
  938. self.assertEqual(Outer.a.value, 1)
  939. self.assertEqual(Outer.Inner.foo.value, 10)
  940. self.assertEqual(
  941. list(Outer.Inner),
  942. [Outer.Inner.foo, Outer.Inner.bar],
  943. )
  944. self.assertEqual(
  945. list(Outer),
  946. [Outer.a, Outer.b],
  947. )
  948. def test_enum_of_types_with_nonmember(self):
  949. """Support using Enum to refer to types deliberately."""
  950. class MyTypes(Enum):
  951. i = int
  952. f = nonmember(float)
  953. s = str
  954. self.assertEqual(MyTypes.i.value, int)
  955. self.assertTrue(MyTypes.f is float)
  956. self.assertEqual(MyTypes.s.value, str)
  957. class Foo:
  958. pass
  959. class Bar:
  960. pass
  961. class MyTypes2(Enum):
  962. a = Foo
  963. b = nonmember(Bar)
  964. self.assertEqual(MyTypes2.a.value, Foo)
  965. self.assertTrue(MyTypes2.b is Bar)
  966. class SpamEnumIsInner:
  967. pass
  968. class SpamEnum(Enum):
  969. spam = nonmember(SpamEnumIsInner)
  970. self.assertTrue(SpamEnum.spam is SpamEnumIsInner)
  971. def test_nested_classes_in_enum_with_member(self):
  972. """Support locally-defined nested classes."""
  973. class Outer(Enum):
  974. a = 1
  975. b = 2
  976. @member
  977. class Inner(Enum):
  978. foo = 10
  979. bar = 11
  980. self.assertTrue(isinstance(Outer.Inner, Outer))
  981. self.assertEqual(Outer.a.value, 1)
  982. self.assertEqual(Outer.Inner.value.foo.value, 10)
  983. self.assertEqual(
  984. list(Outer.Inner.value),
  985. [Outer.Inner.value.foo, Outer.Inner.value.bar],
  986. )
  987. self.assertEqual(
  988. list(Outer),
  989. [Outer.a, Outer.b, Outer.Inner],
  990. )
  991. def test_enum_with_value_name(self):
  992. class Huh(Enum):
  993. name = 1
  994. value = 2
  995. self.assertEqual(list(Huh), [Huh.name, Huh.value])
  996. self.assertIs(type(Huh.name), Huh)
  997. self.assertEqual(Huh.name.name, 'name')
  998. self.assertEqual(Huh.name.value, 1)
  999. def test_inherited_data_type(self):
  1000. class HexInt(int):
  1001. __qualname__ = 'HexInt'
  1002. def __repr__(self):
  1003. return hex(self)
  1004. class MyEnum(HexInt, enum.Enum):
  1005. __qualname__ = 'MyEnum'
  1006. A = 1
  1007. B = 2
  1008. C = 3
  1009. self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
  1010. globals()['HexInt'] = HexInt
  1011. globals()['MyEnum'] = MyEnum
  1012. test_pickle_dump_load(self.assertIs, MyEnum.A)
  1013. test_pickle_dump_load(self.assertIs, MyEnum)
  1014. #
  1015. class SillyInt(HexInt):
  1016. __qualname__ = 'SillyInt'
  1017. pass
  1018. class MyOtherEnum(SillyInt, enum.Enum):
  1019. __qualname__ = 'MyOtherEnum'
  1020. D = 4
  1021. E = 5
  1022. F = 6
  1023. self.assertIs(MyOtherEnum._member_type_, SillyInt)
  1024. globals()['SillyInt'] = SillyInt
  1025. globals()['MyOtherEnum'] = MyOtherEnum
  1026. test_pickle_dump_load(self.assertIs, MyOtherEnum.E)
  1027. test_pickle_dump_load(self.assertIs, MyOtherEnum)
  1028. #
  1029. # This did not work in 3.10, but does now with pickling by name
  1030. class UnBrokenInt(int):
  1031. __qualname__ = 'UnBrokenInt'
  1032. def __new__(cls, value):
  1033. return int.__new__(cls, value)
  1034. class MyUnBrokenEnum(UnBrokenInt, Enum):
  1035. __qualname__ = 'MyUnBrokenEnum'
  1036. G = 7
  1037. H = 8
  1038. I = 9
  1039. self.assertIs(MyUnBrokenEnum._member_type_, UnBrokenInt)
  1040. self.assertIs(MyUnBrokenEnum(7), MyUnBrokenEnum.G)
  1041. globals()['UnBrokenInt'] = UnBrokenInt
  1042. globals()['MyUnBrokenEnum'] = MyUnBrokenEnum
  1043. test_pickle_dump_load(self.assertIs, MyUnBrokenEnum.I)
  1044. test_pickle_dump_load(self.assertIs, MyUnBrokenEnum)
  1045. def test_floatenum_fromhex(self):
  1046. h = float.hex(FloatStooges.MOE.value)
  1047. self.assertIs(FloatStooges.fromhex(h), FloatStooges.MOE)
  1048. h = float.hex(FloatStooges.MOE.value + 0.01)
  1049. with self.assertRaises(ValueError):
  1050. FloatStooges.fromhex(h)
  1051. def test_programmatic_function_type(self):
  1052. MinorEnum = Enum('MinorEnum', 'june july august', type=int)
  1053. lst = list(MinorEnum)
  1054. self.assertEqual(len(lst), len(MinorEnum))
  1055. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1056. self.assertEqual(
  1057. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1058. lst,
  1059. )
  1060. for i, month in enumerate('june july august'.split(), 1):
  1061. e = MinorEnum(i)
  1062. self.assertEqual(e, i)
  1063. self.assertEqual(e.name, month)
  1064. self.assertIn(e, MinorEnum)
  1065. self.assertIs(type(e), MinorEnum)
  1066. def test_programmatic_function_string_with_start(self):
  1067. MinorEnum = Enum('MinorEnum', 'june july august', start=10)
  1068. lst = list(MinorEnum)
  1069. self.assertEqual(len(lst), len(MinorEnum))
  1070. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1071. self.assertEqual(
  1072. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1073. lst,
  1074. )
  1075. for i, month in enumerate('june july august'.split(), 10):
  1076. e = MinorEnum(i)
  1077. self.assertEqual(int(e.value), i)
  1078. self.assertNotEqual(e, i)
  1079. self.assertEqual(e.name, month)
  1080. self.assertIn(e, MinorEnum)
  1081. self.assertIs(type(e), MinorEnum)
  1082. def test_programmatic_function_type_with_start(self):
  1083. MinorEnum = Enum('MinorEnum', 'june july august', type=int, start=30)
  1084. lst = list(MinorEnum)
  1085. self.assertEqual(len(lst), len(MinorEnum))
  1086. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1087. self.assertEqual(
  1088. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1089. lst,
  1090. )
  1091. for i, month in enumerate('june july august'.split(), 30):
  1092. e = MinorEnum(i)
  1093. self.assertEqual(e, i)
  1094. self.assertEqual(e.name, month)
  1095. self.assertIn(e, MinorEnum)
  1096. self.assertIs(type(e), MinorEnum)
  1097. def test_programmatic_function_string_list_with_start(self):
  1098. MinorEnum = Enum('MinorEnum', ['june', 'july', 'august'], start=20)
  1099. lst = list(MinorEnum)
  1100. self.assertEqual(len(lst), len(MinorEnum))
  1101. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1102. self.assertEqual(
  1103. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1104. lst,
  1105. )
  1106. for i, month in enumerate('june july august'.split(), 20):
  1107. e = MinorEnum(i)
  1108. self.assertEqual(int(e.value), i)
  1109. self.assertNotEqual(e, i)
  1110. self.assertEqual(e.name, month)
  1111. self.assertIn(e, MinorEnum)
  1112. self.assertIs(type(e), MinorEnum)
  1113. def test_programmatic_function_type_from_subclass(self):
  1114. MinorEnum = IntEnum('MinorEnum', 'june july august')
  1115. lst = list(MinorEnum)
  1116. self.assertEqual(len(lst), len(MinorEnum))
  1117. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1118. self.assertEqual(
  1119. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1120. lst,
  1121. )
  1122. for i, month in enumerate('june july august'.split(), 1):
  1123. e = MinorEnum(i)
  1124. self.assertEqual(e, i)
  1125. self.assertEqual(e.name, month)
  1126. self.assertIn(e, MinorEnum)
  1127. self.assertIs(type(e), MinorEnum)
  1128. def test_programmatic_function_type_from_subclass_with_start(self):
  1129. MinorEnum = IntEnum('MinorEnum', 'june july august', start=40)
  1130. lst = list(MinorEnum)
  1131. self.assertEqual(len(lst), len(MinorEnum))
  1132. self.assertEqual(len(MinorEnum), 3, MinorEnum)
  1133. self.assertEqual(
  1134. [MinorEnum.june, MinorEnum.july, MinorEnum.august],
  1135. lst,
  1136. )
  1137. for i, month in enumerate('june july august'.split(), 40):
  1138. e = MinorEnum(i)
  1139. self.assertEqual(e, i)
  1140. self.assertEqual(e.name, month)
  1141. self.assertIn(e, MinorEnum)
  1142. self.assertIs(type(e), MinorEnum)
  1143. def test_intenum_from_bytes(self):
  1144. self.assertIs(IntStooges.from_bytes(b'\x00\x03', 'big'), IntStooges.MOE)
  1145. with self.assertRaises(ValueError):
  1146. IntStooges.from_bytes(b'\x00\x05', 'big')
  1147. def test_reserved_sunder_error(self):
  1148. with self.assertRaisesRegex(
  1149. ValueError,
  1150. '_sunder_ names, such as ._bad_., are reserved',
  1151. ):
  1152. class Bad(Enum):
  1153. _bad_ = 1
  1154. def test_too_many_data_types(self):
  1155. with self.assertRaisesRegex(TypeError, 'too many data types'):
  1156. class Huh(str, int, Enum):
  1157. One = 1
  1158. class MyStr(str):
  1159. def hello(self):
  1160. return 'hello, %s' % self
  1161. class MyInt(int):
  1162. def repr(self):
  1163. return hex(self)
  1164. with self.assertRaisesRegex(TypeError, 'too many data types'):
  1165. class Huh(MyStr, MyInt, Enum):
  1166. One = 1
  1167. def test_pickle_enum(self):
  1168. if isinstance(Stooges, Exception):
  1169. raise Stooges
  1170. test_pickle_dump_load(self.assertIs, Stooges.CURLY)
  1171. test_pickle_dump_load(self.assertIs, Stooges)
  1172. def test_pickle_int(self):
  1173. if isinstance(IntStooges, Exception):
  1174. raise IntStooges
  1175. test_pickle_dump_load(self.assertIs, IntStooges.CURLY)
  1176. test_pickle_dump_load(self.assertIs, IntStooges)
  1177. def test_pickle_float(self):
  1178. if isinstance(FloatStooges, Exception):
  1179. raise FloatStooges
  1180. test_pickle_dump_load(self.assertIs, FloatStooges.CURLY)
  1181. test_pickle_dump_load(self.assertIs, FloatStooges)
  1182. def test_pickle_enum_function(self):
  1183. if isinstance(Answer, Exception):
  1184. raise Answer
  1185. test_pickle_dump_load(self.assertIs, Answer.him)
  1186. test_pickle_dump_load(self.assertIs, Answer)
  1187. def test_pickle_enum_function_with_module(self):
  1188. if isinstance(Question, Exception):
  1189. raise Question
  1190. test_pickle_dump_load(self.assertIs, Question.who)
  1191. test_pickle_dump_load(self.assertIs, Question)
  1192. def test_pickle_nested_class(self):
  1193. # would normally just have this directly in the class namespace
  1194. class NestedEnum(Enum):
  1195. twigs = 'common'
  1196. shiny = 'rare'
  1197. self.__class__.NestedEnum = NestedEnum
  1198. self.NestedEnum.__qualname__ = '%s.NestedEnum' % self.__class__.__name__
  1199. test_pickle_dump_load(self.assertIs, self.NestedEnum.twigs)
  1200. def test_pickle_by_name(self):
  1201. class ReplaceGlobalInt(IntEnum):
  1202. ONE = 1
  1203. TWO = 2
  1204. ReplaceGlobalInt.__reduce_ex__ = enum._reduce_ex_by_global_name
  1205. for proto in range(HIGHEST_PROTOCOL):
  1206. self.assertEqual(ReplaceGlobalInt.TWO.__reduce_ex__(proto), 'TWO')
  1207. def test_pickle_explodes(self):
  1208. BadPickle = Enum(
  1209. 'BadPickle', 'dill sweet bread-n-butter', module=__name__)
  1210. globals()['BadPickle'] = BadPickle
  1211. # now break BadPickle to test exception raising
  1212. enum._make_class_unpicklable(BadPickle)
  1213. test_pickle_exception(self.assertRaises, TypeError, BadPickle.dill)
  1214. test_pickle_exception(self.assertRaises, PicklingError, BadPickle)
  1215. def test_string_enum(self):
  1216. class SkillLevel(str, Enum):
  1217. master = 'what is the sound of one hand clapping?'
  1218. journeyman = 'why did the chicken cross the road?'
  1219. apprentice = 'knock, knock!'
  1220. self.assertEqual(SkillLevel.apprentice, 'knock, knock!')
  1221. def test_getattr_getitem(self):
  1222. class Period(Enum):
  1223. morning = 1
  1224. noon = 2
  1225. evening = 3
  1226. night = 4
  1227. self.assertIs(Period(2), Period.noon)
  1228. self.assertIs(getattr(Period, 'night'), Period.night)
  1229. self.assertIs(Period['morning'], Period.morning)
  1230. def test_getattr_dunder(self):
  1231. Season = self.Season
  1232. self.assertTrue(getattr(Season, '__eq__'))
  1233. def test_iteration_order(self):
  1234. class Season(Enum):
  1235. SUMMER = 2
  1236. WINTER = 4
  1237. AUTUMN = 3
  1238. SPRING = 1
  1239. self.assertEqual(
  1240. list(Season),
  1241. [Season.SUMMER, Season.WINTER, Season.AUTUMN, Season.SPRING],
  1242. )
  1243. def test_subclassing(self):
  1244. if isinstance(Name, Exception):
  1245. raise Name
  1246. self.assertEqual(Name.BDFL, 'Guido van Rossum')
  1247. self.assertTrue(Name.BDFL, Name('Guido van Rossum'))
  1248. self.assertIs(Name.BDFL, getattr(Name, 'BDFL'))
  1249. test_pickle_dump_load(self.assertIs, Name.BDFL)
  1250. def test_extending(self):
  1251. class Color(Enum):
  1252. red = 1
  1253. green = 2
  1254. blue = 3
  1255. #
  1256. with self.assertRaises(TypeError):
  1257. class MoreColor(Color):
  1258. cyan = 4
  1259. magenta = 5
  1260. yellow = 6
  1261. #
  1262. with self.assertRaisesRegex(TypeError, "<enum .EvenMoreColor.> cannot extend <enum .Color.>"):
  1263. class EvenMoreColor(Color, IntEnum):
  1264. chartruese = 7
  1265. #
  1266. with self.assertRaisesRegex(TypeError, "<enum .Foo.> cannot extend <enum .Color.>"):
  1267. Color('Foo', ('pink', 'black'))
  1268. def test_exclude_methods(self):
  1269. class whatever(Enum):
  1270. this = 'that'
  1271. these = 'those'
  1272. def really(self):
  1273. return 'no, not %s' % self.value
  1274. self.assertIsNot(type(whatever.really), whatever)
  1275. self.assertEqual(whatever.this.really(), 'no, not that')
  1276. def test_wrong_inheritance_order(self):
  1277. with self.assertRaises(TypeError):
  1278. class Wrong(Enum, str):
  1279. NotHere = 'error before this point'
  1280. def test_intenum_transitivity(self):
  1281. class number(IntEnum):
  1282. one = 1
  1283. two = 2
  1284. three = 3
  1285. class numero(IntEnum):
  1286. uno = 1
  1287. dos = 2
  1288. tres = 3
  1289. self.assertEqual(number.one, numero.uno)
  1290. self.assertEqual(number.two, numero.dos)
  1291. self.assertEqual(number.three, numero.tres)
  1292. def test_wrong_enum_in_call(self):
  1293. class Monochrome(Enum):
  1294. black = 0
  1295. white = 1
  1296. class Gender(Enum):
  1297. male = 0
  1298. female = 1
  1299. self.assertRaises(ValueError, Monochrome, Gender.male)
  1300. def test_wrong_enum_in_mixed_call(self):
  1301. class Monochrome(IntEnum):
  1302. black = 0
  1303. white = 1
  1304. class Gender(Enum):
  1305. male = 0
  1306. female = 1
  1307. self.assertRaises(ValueError, Monochrome, Gender.male)
  1308. def test_mixed_enum_in_call_1(self):
  1309. class Monochrome(IntEnum):
  1310. black = 0
  1311. white = 1
  1312. class Gender(IntEnum):
  1313. male = 0
  1314. female = 1
  1315. self.assertIs(Monochrome(Gender.female), Monochrome.white)
  1316. def test_mixed_enum_in_call_2(self):
  1317. class Monochrome(Enum):
  1318. black = 0
  1319. white = 1
  1320. class Gender(IntEnum):
  1321. male = 0
  1322. female = 1
  1323. self.assertIs(Monochrome(Gender.male), Monochrome.black)
  1324. def test_flufl_enum(self):
  1325. class Fluflnum(Enum):
  1326. def __int__(self):
  1327. return int(self.value)
  1328. class MailManOptions(Fluflnum):
  1329. option1 = 1
  1330. option2 = 2
  1331. option3 = 3
  1332. self.assertEqual(int(MailManOptions.option1), 1)
  1333. def test_introspection(self):
  1334. class Number(IntEnum):
  1335. one = 100
  1336. two = 200
  1337. self.assertIs(Number.one._member_type_, int)
  1338. self.assertIs(Number._member_type_, int)
  1339. class String(str, Enum):
  1340. yarn = 'soft'
  1341. rope = 'rough'
  1342. wire = 'hard'
  1343. self.assertIs(String.yarn._member_type_, str)
  1344. self.assertIs(String._member_type_, str)
  1345. class Plain(Enum):
  1346. vanilla = 'white'
  1347. one = 1
  1348. self.assertIs(Plain.vanilla._member_type_, object)
  1349. self.assertIs(Plain._member_type_, object)
  1350. def test_no_such_enum_member(self):
  1351. class Color(Enum):
  1352. red = 1
  1353. green = 2
  1354. blue = 3
  1355. with self.assertRaises(ValueError):
  1356. Color(4)
  1357. with self.assertRaises(KeyError):
  1358. Color['chartreuse']
  1359. # tests that need to be evalualted for moving
  1360. def test_multiple_mixin_mro(self):
  1361. class auto_enum(type(Enum)):
  1362. def __new__(metacls, cls, bases, classdict):
  1363. temp = type(classdict)()
  1364. temp._cls_name = cls
  1365. names = set(classdict._member_names)
  1366. i = 0
  1367. for k in classdict._member_names:
  1368. v = classdict[k]
  1369. if v is Ellipsis:
  1370. v = i
  1371. else:
  1372. i = v
  1373. i += 1
  1374. temp[k] = v
  1375. for k, v in classdict.items():
  1376. if k not in names:
  1377. temp[k] = v
  1378. return super(auto_enum, metacls).__new__(
  1379. metacls, cls, bases, temp)
  1380. class AutoNumberedEnum(Enum, metaclass=auto_enum):
  1381. pass
  1382. class AutoIntEnum(IntEnum, metaclass=auto_enum):
  1383. pass
  1384. class TestAutoNumber(AutoNumberedEnum):
  1385. a = ...
  1386. b = 3
  1387. c = ...
  1388. class TestAutoInt(AutoIntEnum):
  1389. a = ...
  1390. b = 3
  1391. c = ...
  1392. def test_subclasses_with_getnewargs(self):
  1393. class NamedInt(int):
  1394. __qualname__ = 'NamedInt' # needed for pickle protocol 4
  1395. def __new__(cls, *args):
  1396. _args = args
  1397. name, *args = args
  1398. if len(args) == 0:
  1399. raise TypeError("name and value must be specified")
  1400. self = int.__new__(cls, *args)
  1401. self._intname = name
  1402. self._args = _args
  1403. return self
  1404. def __getnewargs__(self):
  1405. return self._args
  1406. @bltns.property
  1407. def __name__(self):
  1408. return self._intname
  1409. def __repr__(self):
  1410. # repr() is updated to include the name and type info
  1411. return "{}({!r}, {})".format(
  1412. type(self).__name__,
  1413. self.__name__,
  1414. int.__repr__(self),
  1415. )
  1416. def __str__(self):
  1417. # str() is unchanged, even if it relies on the repr() fallback
  1418. base = int
  1419. base_str = base.__str__
  1420. if base_str.__objclass__ is object:
  1421. return base.__repr__(self)
  1422. return base_str(self)
  1423. # for simplicity, we only define one operator that
  1424. # propagates expressions
  1425. def __add__(self, other):
  1426. temp = int(self) + int( other)
  1427. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1428. return NamedInt(
  1429. '({0} + {1})'.format(self.__name__, other.__name__),
  1430. temp,
  1431. )
  1432. else:
  1433. return temp
  1434. class NEI(NamedInt, Enum):
  1435. __qualname__ = 'NEI' # needed for pickle protocol 4
  1436. x = ('the-x', 1)
  1437. y = ('the-y', 2)
  1438. self.assertIs(NEI.__new__, Enum.__new__)
  1439. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1440. globals()['NamedInt'] = NamedInt
  1441. globals()['NEI'] = NEI
  1442. NI5 = NamedInt('test', 5)
  1443. self.assertEqual(NI5, 5)
  1444. test_pickle_dump_load(self.assertEqual, NI5, 5)
  1445. self.assertEqual(NEI.y.value, 2)
  1446. test_pickle_dump_load(self.assertIs, NEI.y)
  1447. test_pickle_dump_load(self.assertIs, NEI)
  1448. def test_subclasses_with_getnewargs_ex(self):
  1449. class NamedInt(int):
  1450. __qualname__ = 'NamedInt' # needed for pickle protocol 4
  1451. def __new__(cls, *args):
  1452. _args = args
  1453. name, *args = args
  1454. if len(args) == 0:
  1455. raise TypeError("name and value must be specified")
  1456. self = int.__new__(cls, *args)
  1457. self._intname = name
  1458. self._args = _args
  1459. return self
  1460. def __getnewargs_ex__(self):
  1461. return self._args, {}
  1462. @bltns.property
  1463. def __name__(self):
  1464. return self._intname
  1465. def __repr__(self):
  1466. # repr() is updated to include the name and type info
  1467. return "{}({!r}, {})".format(
  1468. type(self).__name__,
  1469. self.__name__,
  1470. int.__repr__(self),
  1471. )
  1472. def __str__(self):
  1473. # str() is unchanged, even if it relies on the repr() fallback
  1474. base = int
  1475. base_str = base.__str__
  1476. if base_str.__objclass__ is object:
  1477. return base.__repr__(self)
  1478. return base_str(self)
  1479. # for simplicity, we only define one operator that
  1480. # propagates expressions
  1481. def __add__(self, other):
  1482. temp = int(self) + int( other)
  1483. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1484. return NamedInt(
  1485. '({0} + {1})'.format(self.__name__, other.__name__),
  1486. temp,
  1487. )
  1488. else:
  1489. return temp
  1490. class NEI(NamedInt, Enum):
  1491. __qualname__ = 'NEI' # needed for pickle protocol 4
  1492. x = ('the-x', 1)
  1493. y = ('the-y', 2)
  1494. self.assertIs(NEI.__new__, Enum.__new__)
  1495. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1496. globals()['NamedInt'] = NamedInt
  1497. globals()['NEI'] = NEI
  1498. NI5 = NamedInt('test', 5)
  1499. self.assertEqual(NI5, 5)
  1500. test_pickle_dump_load(self.assertEqual, NI5, 5)
  1501. self.assertEqual(NEI.y.value, 2)
  1502. test_pickle_dump_load(self.assertIs, NEI.y)
  1503. test_pickle_dump_load(self.assertIs, NEI)
  1504. def test_subclasses_with_reduce(self):
  1505. class NamedInt(int):
  1506. __qualname__ = 'NamedInt' # needed for pickle protocol 4
  1507. def __new__(cls, *args):
  1508. _args = args
  1509. name, *args = args
  1510. if len(args) == 0:
  1511. raise TypeError("name and value must be specified")
  1512. self = int.__new__(cls, *args)
  1513. self._intname = name
  1514. self._args = _args
  1515. return self
  1516. def __reduce__(self):
  1517. return self.__class__, self._args
  1518. @bltns.property
  1519. def __name__(self):
  1520. return self._intname
  1521. def __repr__(self):
  1522. # repr() is updated to include the name and type info
  1523. return "{}({!r}, {})".format(
  1524. type(self).__name__,
  1525. self.__name__,
  1526. int.__repr__(self),
  1527. )
  1528. def __str__(self):
  1529. # str() is unchanged, even if it relies on the repr() fallback
  1530. base = int
  1531. base_str = base.__str__
  1532. if base_str.__objclass__ is object:
  1533. return base.__repr__(self)
  1534. return base_str(self)
  1535. # for simplicity, we only define one operator that
  1536. # propagates expressions
  1537. def __add__(self, other):
  1538. temp = int(self) + int( other)
  1539. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1540. return NamedInt(
  1541. '({0} + {1})'.format(self.__name__, other.__name__),
  1542. temp,
  1543. )
  1544. else:
  1545. return temp
  1546. class NEI(NamedInt, Enum):
  1547. __qualname__ = 'NEI' # needed for pickle protocol 4
  1548. x = ('the-x', 1)
  1549. y = ('the-y', 2)
  1550. self.assertIs(NEI.__new__, Enum.__new__)
  1551. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1552. globals()['NamedInt'] = NamedInt
  1553. globals()['NEI'] = NEI
  1554. NI5 = NamedInt('test', 5)
  1555. self.assertEqual(NI5, 5)
  1556. test_pickle_dump_load(self.assertEqual, NI5, 5)
  1557. self.assertEqual(NEI.y.value, 2)
  1558. test_pickle_dump_load(self.assertIs, NEI.y)
  1559. test_pickle_dump_load(self.assertIs, NEI)
  1560. def test_subclasses_with_reduce_ex(self):
  1561. class NamedInt(int):
  1562. __qualname__ = 'NamedInt' # needed for pickle protocol 4
  1563. def __new__(cls, *args):
  1564. _args = args
  1565. name, *args = args
  1566. if len(args) == 0:
  1567. raise TypeError("name and value must be specified")
  1568. self = int.__new__(cls, *args)
  1569. self._intname = name
  1570. self._args = _args
  1571. return self
  1572. def __reduce_ex__(self, proto):
  1573. return self.__class__, self._args
  1574. @bltns.property
  1575. def __name__(self):
  1576. return self._intname
  1577. def __repr__(self):
  1578. # repr() is updated to include the name and type info
  1579. return "{}({!r}, {})".format(
  1580. type(self).__name__,
  1581. self.__name__,
  1582. int.__repr__(self),
  1583. )
  1584. def __str__(self):
  1585. # str() is unchanged, even if it relies on the repr() fallback
  1586. base = int
  1587. base_str = base.__str__
  1588. if base_str.__objclass__ is object:
  1589. return base.__repr__(self)
  1590. return base_str(self)
  1591. # for simplicity, we only define one operator that
  1592. # propagates expressions
  1593. def __add__(self, other):
  1594. temp = int(self) + int( other)
  1595. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1596. return NamedInt(
  1597. '({0} + {1})'.format(self.__name__, other.__name__),
  1598. temp,
  1599. )
  1600. else:
  1601. return temp
  1602. class NEI(NamedInt, Enum):
  1603. __qualname__ = 'NEI' # needed for pickle protocol 4
  1604. x = ('the-x', 1)
  1605. y = ('the-y', 2)
  1606. self.assertIs(NEI.__new__, Enum.__new__)
  1607. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1608. globals()['NamedInt'] = NamedInt
  1609. globals()['NEI'] = NEI
  1610. NI5 = NamedInt('test', 5)
  1611. self.assertEqual(NI5, 5)
  1612. test_pickle_dump_load(self.assertEqual, NI5, 5)
  1613. self.assertEqual(NEI.y.value, 2)
  1614. test_pickle_dump_load(self.assertIs, NEI.y)
  1615. test_pickle_dump_load(self.assertIs, NEI)
  1616. def test_subclasses_without_direct_pickle_support(self):
  1617. class NamedInt(int):
  1618. __qualname__ = 'NamedInt'
  1619. def __new__(cls, *args):
  1620. _args = args
  1621. name, *args = args
  1622. if len(args) == 0:
  1623. raise TypeError("name and value must be specified")
  1624. self = int.__new__(cls, *args)
  1625. self._intname = name
  1626. self._args = _args
  1627. return self
  1628. @bltns.property
  1629. def __name__(self):
  1630. return self._intname
  1631. def __repr__(self):
  1632. # repr() is updated to include the name and type info
  1633. return "{}({!r}, {})".format(
  1634. type(self).__name__,
  1635. self.__name__,
  1636. int.__repr__(self),
  1637. )
  1638. def __str__(self):
  1639. # str() is unchanged, even if it relies on the repr() fallback
  1640. base = int
  1641. base_str = base.__str__
  1642. if base_str.__objclass__ is object:
  1643. return base.__repr__(self)
  1644. return base_str(self)
  1645. # for simplicity, we only define one operator that
  1646. # propagates expressions
  1647. def __add__(self, other):
  1648. temp = int(self) + int( other)
  1649. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1650. return NamedInt(
  1651. '({0} + {1})'.format(self.__name__, other.__name__),
  1652. temp )
  1653. else:
  1654. return temp
  1655. class NEI(NamedInt, Enum):
  1656. __qualname__ = 'NEI'
  1657. x = ('the-x', 1)
  1658. y = ('the-y', 2)
  1659. self.assertIs(NEI.__new__, Enum.__new__)
  1660. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1661. globals()['NamedInt'] = NamedInt
  1662. globals()['NEI'] = NEI
  1663. NI5 = NamedInt('test', 5)
  1664. self.assertEqual(NI5, 5)
  1665. self.assertEqual(NEI.y.value, 2)
  1666. test_pickle_dump_load(self.assertIs, NEI.y)
  1667. test_pickle_dump_load(self.assertIs, NEI)
  1668. def test_subclasses_with_direct_pickle_support(self):
  1669. class NamedInt(int):
  1670. __qualname__ = 'NamedInt'
  1671. def __new__(cls, *args):
  1672. _args = args
  1673. name, *args = args
  1674. if len(args) == 0:
  1675. raise TypeError("name and value must be specified")
  1676. self = int.__new__(cls, *args)
  1677. self._intname = name
  1678. self._args = _args
  1679. return self
  1680. @bltns.property
  1681. def __name__(self):
  1682. return self._intname
  1683. def __repr__(self):
  1684. # repr() is updated to include the name and type info
  1685. return "{}({!r}, {})".format(
  1686. type(self).__name__,
  1687. self.__name__,
  1688. int.__repr__(self),
  1689. )
  1690. def __str__(self):
  1691. # str() is unchanged, even if it relies on the repr() fallback
  1692. base = int
  1693. base_str = base.__str__
  1694. if base_str.__objclass__ is object:
  1695. return base.__repr__(self)
  1696. return base_str(self)
  1697. # for simplicity, we only define one operator that
  1698. # propagates expressions
  1699. def __add__(self, other):
  1700. temp = int(self) + int( other)
  1701. if isinstance(self, NamedInt) and isinstance(other, NamedInt):
  1702. return NamedInt(
  1703. '({0} + {1})'.format(self.__name__, other.__name__),
  1704. temp,
  1705. )
  1706. else:
  1707. return temp
  1708. class NEI(NamedInt, Enum):
  1709. __qualname__ = 'NEI'
  1710. x = ('the-x', 1)
  1711. y = ('the-y', 2)
  1712. def __reduce_ex__(self, proto):
  1713. return getattr, (self.__class__, self._name_)
  1714. self.assertIs(NEI.__new__, Enum.__new__)
  1715. self.assertEqual(repr(NEI.x + NEI.y), "NamedInt('(the-x + the-y)', 3)")
  1716. globals()['NamedInt'] = NamedInt
  1717. globals()['NEI'] = NEI
  1718. NI5 = NamedInt('test', 5)
  1719. self.assertEqual(NI5, 5)
  1720. self.assertEqual(NEI.y.value, 2)
  1721. test_pickle_dump_load(self.assertIs, NEI.y)
  1722. test_pickle_dump_load(self.assertIs, NEI)
  1723. def test_tuple_subclass(self):
  1724. class SomeTuple(tuple, Enum):
  1725. __qualname__ = 'SomeTuple' # needed for pickle protocol 4
  1726. first = (1, 'for the money')
  1727. second = (2, 'for the show')
  1728. third = (3, 'for the music')
  1729. self.assertIs(type(SomeTuple.first), SomeTuple)
  1730. self.assertIsInstance(SomeTuple.second, tuple)
  1731. self.assertEqual(SomeTuple.third, (3, 'for the music'))
  1732. globals()['SomeTuple'] = SomeTuple
  1733. test_pickle_dump_load(self.assertIs, SomeTuple.first)
  1734. def test_duplicate_values_give_unique_enum_items(self):
  1735. class AutoNumber(Enum):
  1736. first = ()
  1737. second = ()
  1738. third = ()
  1739. def __new__(cls):
  1740. value = len(cls.__members__) + 1
  1741. obj = object.__new__(cls)
  1742. obj._value_ = value
  1743. return obj
  1744. def __int__(self):
  1745. return int(self._value_)
  1746. self.assertEqual(
  1747. list(AutoNumber),
  1748. [AutoNumber.first, AutoNumber.second, AutoNumber.third],
  1749. )
  1750. self.assertEqual(int(AutoNumber.second), 2)
  1751. self.assertEqual(AutoNumber.third.value, 3)
  1752. self.assertIs(AutoNumber(1), AutoNumber.first)
  1753. def test_inherited_new_from_enhanced_enum(self):
  1754. class AutoNumber(Enum):
  1755. def __new__(cls):
  1756. value = len(cls.__members__) + 1
  1757. obj = object.__new__(cls)
  1758. obj._value_ = value
  1759. return obj
  1760. def __int__(self):
  1761. return int(self._value_)
  1762. class Color(AutoNumber):
  1763. red = ()
  1764. green = ()
  1765. blue = ()
  1766. self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
  1767. self.assertEqual(list(map(int, Color)), [1, 2, 3])
  1768. def test_inherited_new_from_mixed_enum(self):
  1769. class AutoNumber(IntEnum):
  1770. def __new__(cls):
  1771. value = len(cls.__members__) + 1
  1772. obj = int.__new__(cls, value)
  1773. obj._value_ = value
  1774. return obj
  1775. class Color(AutoNumber):
  1776. red = ()
  1777. green = ()
  1778. blue = ()
  1779. self.assertEqual(list(Color), [Color.red, Color.green, Color.blue])
  1780. self.assertEqual(list(map(int, Color)), [1, 2, 3])
  1781. def test_equality(self):
  1782. class OrdinaryEnum(Enum):
  1783. a = 1
  1784. self.assertEqual(ALWAYS_EQ, OrdinaryEnum.a)
  1785. self.assertEqual(OrdinaryEnum.a, ALWAYS_EQ)
  1786. def test_ordered_mixin(self):
  1787. class OrderedEnum(Enum):
  1788. def __ge__(self, other):
  1789. if self.__class__ is other.__class__:
  1790. return self._value_ >= other._value_
  1791. return NotImplemented
  1792. def __gt__(self, other):
  1793. if self.__class__ is other.__class__:
  1794. return self._value_ > other._value_
  1795. return NotImplemented
  1796. def __le__(self, other):
  1797. if self.__class__ is other.__class__:
  1798. return self._value_ <= other._value_
  1799. return NotImplemented
  1800. def __lt__(self, other):
  1801. if self.__class__ is other.__class__:
  1802. return self._value_ < other._value_
  1803. return NotImplemented
  1804. class Grade(OrderedEnum):
  1805. A = 5
  1806. B = 4
  1807. C = 3
  1808. D = 2
  1809. F = 1
  1810. self.assertGreater(Grade.A, Grade.B)
  1811. self.assertLessEqual(Grade.F, Grade.C)
  1812. self.assertLess(Grade.D, Grade.A)
  1813. self.assertGreaterEqual(Grade.B, Grade.B)
  1814. self.assertEqual(Grade.B, Grade.B)
  1815. self.assertNotEqual(Grade.C, Grade.D)
  1816. def test_extending2(self):
  1817. class Shade(Enum):
  1818. def shade(self):
  1819. print(self.name)
  1820. class Color(Shade):
  1821. red = 1
  1822. green = 2
  1823. blue = 3
  1824. with self.assertRaises(TypeError):
  1825. class MoreColor(Color):
  1826. cyan = 4
  1827. magenta = 5
  1828. yellow = 6
  1829. def test_extending3(self):
  1830. class Shade(Enum):
  1831. def shade(self):
  1832. return self.name
  1833. class Color(Shade):
  1834. def hex(self):
  1835. return '%s hexlified!' % self.value
  1836. class MoreColor(Color):
  1837. cyan = 4
  1838. magenta = 5
  1839. yellow = 6
  1840. self.assertEqual(MoreColor.magenta.hex(), '5 hexlified!')
  1841. def test_subclass_duplicate_name(self):
  1842. class Base(Enum):
  1843. def test(self):
  1844. pass
  1845. class Test(Base):
  1846. test = 1
  1847. self.assertIs(type(Test.test), Test)
  1848. def test_subclass_duplicate_name_dynamic(self):
  1849. from types import DynamicClassAttribute
  1850. class Base(Enum):
  1851. @DynamicClassAttribute
  1852. def test(self):
  1853. return 'dynamic'
  1854. class Test(Base):
  1855. test = 1
  1856. self.assertEqual(Test.test.test, 'dynamic')
  1857. self.assertEqual(Test.test.value, 1)
  1858. class Base2(Enum):
  1859. @enum.property
  1860. def flash(self):
  1861. return 'flashy dynamic'
  1862. class Test(Base2):
  1863. flash = 1
  1864. self.assertEqual(Test.flash.flash, 'flashy dynamic')
  1865. self.assertEqual(Test.flash.value, 1)
  1866. def test_no_duplicates(self):
  1867. class UniqueEnum(Enum):
  1868. def __init__(self, *args):
  1869. cls = self.__class__
  1870. if any(self.value == e.value for e in cls):
  1871. a = self.name
  1872. e = cls(self.value).name
  1873. raise ValueError(
  1874. "aliases not allowed in UniqueEnum: %r --> %r"
  1875. % (a, e)
  1876. )
  1877. class Color(UniqueEnum):
  1878. red = 1
  1879. green = 2
  1880. blue = 3
  1881. with self.assertRaises(ValueError):
  1882. class Color(UniqueEnum):
  1883. red = 1
  1884. green = 2
  1885. blue = 3
  1886. grene = 2
  1887. def test_init(self):
  1888. class Planet(Enum):
  1889. MERCURY = (3.303e+23, 2.4397e6)
  1890. VENUS = (4.869e+24, 6.0518e6)
  1891. EARTH = (5.976e+24, 6.37814e6)
  1892. MARS = (6.421e+23, 3.3972e6)
  1893. JUPITER = (1.9e+27, 7.1492e7)
  1894. SATURN = (5.688e+26, 6.0268e7)
  1895. URANUS = (8.686e+25, 2.5559e7)
  1896. NEPTUNE = (1.024e+26, 2.4746e7)
  1897. def __init__(self, mass, radius):
  1898. self.mass = mass # in kilograms
  1899. self.radius = radius # in meters
  1900. @enum.property
  1901. def surface_gravity(self):
  1902. # universal gravitational constant (m3 kg-1 s-2)
  1903. G = 6.67300E-11
  1904. return G * self.mass / (self.radius * self.radius)
  1905. self.assertEqual(round(Planet.EARTH.surface_gravity, 2), 9.80)
  1906. self.assertEqual(Planet.EARTH.value, (5.976e+24, 6.37814e6))
  1907. def test_ignore(self):
  1908. class Period(timedelta, Enum):
  1909. '''
  1910. different lengths of time
  1911. '''
  1912. def __new__(cls, value, period):
  1913. obj = timedelta.__new__(cls, value)
  1914. obj._value_ = value
  1915. obj.period = period
  1916. return obj
  1917. _ignore_ = 'Period i'
  1918. Period = vars()
  1919. for i in range(13):
  1920. Period['month_%d' % i] = i*30, 'month'
  1921. for i in range(53):
  1922. Period['week_%d' % i] = i*7, 'week'
  1923. for i in range(32):
  1924. Period['day_%d' % i] = i, 'day'
  1925. OneDay = day_1
  1926. OneWeek = week_1
  1927. OneMonth = month_1
  1928. self.assertFalse(hasattr(Period, '_ignore_'))
  1929. self.assertFalse(hasattr(Period, 'Period'))
  1930. self.assertFalse(hasattr(Period, 'i'))
  1931. self.assertTrue(isinstance(Period.day_1, timedelta))
  1932. self.assertTrue(Period.month_1 is Period.day_30)
  1933. self.assertTrue(Period.week_4 is Period.day_28)
  1934. def test_nonhash_value(self):
  1935. class AutoNumberInAList(Enum):
  1936. def __new__(cls):
  1937. value = [len(cls.__members__) + 1]
  1938. obj = object.__new__(cls)
  1939. obj._value_ = value
  1940. return obj
  1941. class ColorInAList(AutoNumberInAList):
  1942. red = ()
  1943. green = ()
  1944. blue = ()
  1945. self.assertEqual(list(ColorInAList), [ColorInAList.red, ColorInAList.green, ColorInAList.blue])
  1946. for enum, value in zip(ColorInAList, range(3)):
  1947. value += 1
  1948. self.assertEqual(enum.value, [value])
  1949. self.assertIs(ColorInAList([value]), enum)
  1950. def test_conflicting_types_resolved_in_new(self):
  1951. class LabelledIntEnum(int, Enum):
  1952. def __new__(cls, *args):
  1953. value, label = args
  1954. obj = int.__new__(cls, value)
  1955. obj.label = label
  1956. obj._value_ = value
  1957. return obj
  1958. class LabelledList(LabelledIntEnum):
  1959. unprocessed = (1, "Unprocessed")
  1960. payment_complete = (2, "Payment Complete")
  1961. self.assertEqual(list(LabelledList), [LabelledList.unprocessed, LabelledList.payment_complete])
  1962. self.assertEqual(LabelledList.unprocessed, 1)
  1963. self.assertEqual(LabelledList(1), LabelledList.unprocessed)
  1964. def test_default_missing_no_chained_exception(self):
  1965. class Color(Enum):
  1966. RED = 1
  1967. GREEN = 2
  1968. BLUE = 3
  1969. try:
  1970. Color(7)
  1971. except ValueError as exc:
  1972. self.assertTrue(exc.__context__ is None)
  1973. else:
  1974. raise Exception('Exception not raised.')
  1975. def test_missing_override(self):
  1976. class Color(Enum):
  1977. red = 1
  1978. green = 2
  1979. blue = 3
  1980. @classmethod
  1981. def _missing_(cls, item):
  1982. if item == 'three':
  1983. return cls.blue
  1984. elif item == 'bad return':
  1985. # trigger internal error
  1986. return 5
  1987. elif item == 'error out':
  1988. raise ZeroDivisionError
  1989. else:
  1990. # trigger not found
  1991. return None
  1992. self.assertIs(Color('three'), Color.blue)
  1993. try:
  1994. Color(7)
  1995. except ValueError as exc:
  1996. self.assertTrue(exc.__context__ is None)
  1997. else:
  1998. raise Exception('Exception not raised.')
  1999. try:
  2000. Color('bad return')
  2001. except TypeError as exc:
  2002. self.assertTrue(isinstance(exc.__context__, ValueError))
  2003. else:
  2004. raise Exception('Exception not raised.')
  2005. try:
  2006. Color('error out')
  2007. except ZeroDivisionError as exc:
  2008. self.assertTrue(isinstance(exc.__context__, ValueError))
  2009. else:
  2010. raise Exception('Exception not raised.')
  2011. def test_missing_exceptions_reset(self):
  2012. import gc
  2013. import weakref
  2014. #
  2015. class TestEnum(enum.Enum):
  2016. VAL1 = 'val1'
  2017. VAL2 = 'val2'
  2018. #
  2019. class Class1:
  2020. def __init__(self):
  2021. # Gracefully handle an exception of our own making
  2022. try:
  2023. raise ValueError()
  2024. except ValueError:
  2025. pass
  2026. #
  2027. class Class2:
  2028. def __init__(self):
  2029. # Gracefully handle an exception of Enum's making
  2030. try:
  2031. TestEnum('invalid_value')
  2032. except ValueError:
  2033. pass
  2034. # No strong refs here so these are free to die.
  2035. class_1_ref = weakref.ref(Class1())
  2036. class_2_ref = weakref.ref(Class2())
  2037. #
  2038. # The exception raised by Enum used to create a reference loop and thus
  2039. # Class2 instances would stick around until the next garbage collection
  2040. # cycle, unlike Class1. Verify Class2 no longer does this.
  2041. gc.collect() # For PyPy or other GCs.
  2042. self.assertIs(class_1_ref(), None)
  2043. self.assertIs(class_2_ref(), None)
  2044. def test_multiple_mixin(self):
  2045. class MaxMixin:
  2046. @classproperty
  2047. def MAX(cls):
  2048. max = len(cls)
  2049. cls.MAX = max
  2050. return max
  2051. class StrMixin:
  2052. def __str__(self):
  2053. return self._name_.lower()
  2054. class SomeEnum(Enum):
  2055. def behavior(self):
  2056. return 'booyah'
  2057. class AnotherEnum(Enum):
  2058. def behavior(self):
  2059. return 'nuhuh!'
  2060. def social(self):
  2061. return "what's up?"
  2062. class Color(MaxMixin, Enum):
  2063. RED = auto()
  2064. GREEN = auto()
  2065. BLUE = auto()
  2066. self.assertEqual(Color.RED.value, 1)
  2067. self.assertEqual(Color.GREEN.value, 2)
  2068. self.assertEqual(Color.BLUE.value, 3)
  2069. self.assertEqual(Color.MAX, 3)
  2070. self.assertEqual(str(Color.BLUE), 'Color.BLUE')
  2071. class Color(MaxMixin, StrMixin, Enum):
  2072. RED = auto()
  2073. GREEN = auto()
  2074. BLUE = auto()
  2075. __str__ = StrMixin.__str__ # needed as of 3.11
  2076. self.assertEqual(Color.RED.value, 1)
  2077. self.assertEqual(Color.GREEN.value, 2)
  2078. self.assertEqual(Color.BLUE.value, 3)
  2079. self.assertEqual(Color.MAX, 3)
  2080. self.assertEqual(str(Color.BLUE), 'blue')
  2081. class Color(StrMixin, MaxMixin, Enum):
  2082. RED = auto()
  2083. GREEN = auto()
  2084. BLUE = auto()
  2085. __str__ = StrMixin.__str__ # needed as of 3.11
  2086. self.assertEqual(Color.RED.value, 1)
  2087. self.assertEqual(Color.GREEN.value, 2)
  2088. self.assertEqual(Color.BLUE.value, 3)
  2089. self.assertEqual(Color.MAX, 3)
  2090. self.assertEqual(str(Color.BLUE), 'blue')
  2091. class CoolColor(StrMixin, SomeEnum, Enum):
  2092. RED = auto()
  2093. GREEN = auto()
  2094. BLUE = auto()
  2095. __str__ = StrMixin.__str__ # needed as of 3.11
  2096. self.assertEqual(CoolColor.RED.value, 1)
  2097. self.assertEqual(CoolColor.GREEN.value, 2)
  2098. self.assertEqual(CoolColor.BLUE.value, 3)
  2099. self.assertEqual(str(CoolColor.BLUE), 'blue')
  2100. self.assertEqual(CoolColor.RED.behavior(), 'booyah')
  2101. class CoolerColor(StrMixin, AnotherEnum, Enum):
  2102. RED = auto()
  2103. GREEN = auto()
  2104. BLUE = auto()
  2105. __str__ = StrMixin.__str__ # needed as of 3.11
  2106. self.assertEqual(CoolerColor.RED.value, 1)
  2107. self.assertEqual(CoolerColor.GREEN.value, 2)
  2108. self.assertEqual(CoolerColor.BLUE.value, 3)
  2109. self.assertEqual(str(CoolerColor.BLUE), 'blue')
  2110. self.assertEqual(CoolerColor.RED.behavior(), 'nuhuh!')
  2111. self.assertEqual(CoolerColor.RED.social(), "what's up?")
  2112. class CoolestColor(StrMixin, SomeEnum, AnotherEnum):
  2113. RED = auto()
  2114. GREEN = auto()
  2115. BLUE = auto()
  2116. __str__ = StrMixin.__str__ # needed as of 3.11
  2117. self.assertEqual(CoolestColor.RED.value, 1)
  2118. self.assertEqual(CoolestColor.GREEN.value, 2)
  2119. self.assertEqual(CoolestColor.BLUE.value, 3)
  2120. self.assertEqual(str(CoolestColor.BLUE), 'blue')
  2121. self.assertEqual(CoolestColor.RED.behavior(), 'booyah')
  2122. self.assertEqual(CoolestColor.RED.social(), "what's up?")
  2123. class ConfusedColor(StrMixin, AnotherEnum, SomeEnum):
  2124. RED = auto()
  2125. GREEN = auto()
  2126. BLUE = auto()
  2127. __str__ = StrMixin.__str__ # needed as of 3.11
  2128. self.assertEqual(ConfusedColor.RED.value, 1)
  2129. self.assertEqual(ConfusedColor.GREEN.value, 2)
  2130. self.assertEqual(ConfusedColor.BLUE.value, 3)
  2131. self.assertEqual(str(ConfusedColor.BLUE), 'blue')
  2132. self.assertEqual(ConfusedColor.RED.behavior(), 'nuhuh!')
  2133. self.assertEqual(ConfusedColor.RED.social(), "what's up?")
  2134. class ReformedColor(StrMixin, IntEnum, SomeEnum, AnotherEnum):
  2135. RED = auto()
  2136. GREEN = auto()
  2137. BLUE = auto()
  2138. __str__ = StrMixin.__str__ # needed as of 3.11
  2139. self.assertEqual(ReformedColor.RED.value, 1)
  2140. self.assertEqual(ReformedColor.GREEN.value, 2)
  2141. self.assertEqual(ReformedColor.BLUE.value, 3)
  2142. self.assertEqual(str(ReformedColor.BLUE), 'blue')
  2143. self.assertEqual(ReformedColor.RED.behavior(), 'booyah')
  2144. self.assertEqual(ConfusedColor.RED.social(), "what's up?")
  2145. self.assertTrue(issubclass(ReformedColor, int))
  2146. def test_multiple_inherited_mixin(self):
  2147. @unique
  2148. class Decision1(StrEnum):
  2149. REVERT = "REVERT"
  2150. REVERT_ALL = "REVERT_ALL"
  2151. RETRY = "RETRY"
  2152. class MyEnum(StrEnum):
  2153. pass
  2154. @unique
  2155. class Decision2(MyEnum):
  2156. REVERT = "REVERT"
  2157. REVERT_ALL = "REVERT_ALL"
  2158. RETRY = "RETRY"
  2159. def test_multiple_mixin_inherited(self):
  2160. class MyInt(int):
  2161. def __new__(cls, value):
  2162. return super().__new__(cls, value)
  2163. class HexMixin:
  2164. def __repr__(self):
  2165. return hex(self)
  2166. class MyIntEnum(HexMixin, MyInt, enum.Enum):
  2167. __repr__ = HexMixin.__repr__
  2168. class Foo(MyIntEnum):
  2169. TEST = 1
  2170. self.assertTrue(isinstance(Foo.TEST, MyInt))
  2171. self.assertEqual(Foo._member_type_, MyInt)
  2172. self.assertEqual(repr(Foo.TEST), "0x1")
  2173. class Fee(MyIntEnum):
  2174. TEST = 1
  2175. def __new__(cls, value):
  2176. value += 1
  2177. member = int.__new__(cls, value)
  2178. member._value_ = value
  2179. return member
  2180. self.assertEqual(Fee.TEST, 2)
  2181. def test_multiple_mixin_with_common_data_type(self):
  2182. class CaseInsensitiveStrEnum(str, Enum):
  2183. @classmethod
  2184. def _missing_(cls, value):
  2185. for member in cls._member_map_.values():
  2186. if member._value_.lower() == value.lower():
  2187. return member
  2188. return super()._missing_(value)
  2189. #
  2190. class LenientStrEnum(str, Enum):
  2191. def __init__(self, *args):
  2192. self._valid = True
  2193. @classmethod
  2194. def _missing_(cls, value):
  2195. unknown = cls._member_type_.__new__(cls, value)
  2196. unknown._valid = False
  2197. unknown._name_ = value.upper()
  2198. unknown._value_ = value
  2199. cls._member_map_[value] = unknown
  2200. return unknown
  2201. @enum.property
  2202. def valid(self):
  2203. return self._valid
  2204. #
  2205. class JobStatus(CaseInsensitiveStrEnum, LenientStrEnum):
  2206. ACTIVE = "active"
  2207. PENDING = "pending"
  2208. TERMINATED = "terminated"
  2209. #
  2210. JS = JobStatus
  2211. self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
  2212. self.assertEqual(JS.ACTIVE, 'active')
  2213. self.assertEqual(JS.ACTIVE.value, 'active')
  2214. self.assertIs(JS('Active'), JS.ACTIVE)
  2215. self.assertTrue(JS.ACTIVE.valid)
  2216. missing = JS('missing')
  2217. self.assertEqual(list(JobStatus), [JS.ACTIVE, JS.PENDING, JS.TERMINATED])
  2218. self.assertEqual(JS.ACTIVE, 'active')
  2219. self.assertEqual(JS.ACTIVE.value, 'active')
  2220. self.assertIs(JS('Active'), JS.ACTIVE)
  2221. self.assertTrue(JS.ACTIVE.valid)
  2222. self.assertTrue(isinstance(missing, JS))
  2223. self.assertFalse(missing.valid)
  2224. def test_empty_globals(self):
  2225. # bpo-35717: sys._getframe(2).f_globals['__name__'] fails with KeyError
  2226. # when using compile and exec because f_globals is empty
  2227. code = "from enum import Enum; Enum('Animal', 'ANT BEE CAT DOG')"
  2228. code = compile(code, "<string>", "exec")
  2229. global_ns = {}
  2230. local_ls = {}
  2231. exec(code, global_ns, local_ls)
  2232. def test_strenum(self):
  2233. class GoodStrEnum(StrEnum):
  2234. one = '1'
  2235. two = '2'
  2236. three = b'3', 'ascii'
  2237. four = b'4', 'latin1', 'strict'
  2238. self.assertEqual(GoodStrEnum.one, '1')
  2239. self.assertEqual(str(GoodStrEnum.one), '1')
  2240. self.assertEqual('{}'.format(GoodStrEnum.one), '1')
  2241. self.assertEqual(GoodStrEnum.one, str(GoodStrEnum.one))
  2242. self.assertEqual(GoodStrEnum.one, '{}'.format(GoodStrEnum.one))
  2243. self.assertEqual(repr(GoodStrEnum.one), "<GoodStrEnum.one: '1'>")
  2244. #
  2245. class DumbMixin:
  2246. def __str__(self):
  2247. return "don't do this"
  2248. class DumbStrEnum(DumbMixin, StrEnum):
  2249. five = '5'
  2250. six = '6'
  2251. seven = '7'
  2252. __str__ = DumbMixin.__str__ # needed as of 3.11
  2253. self.assertEqual(DumbStrEnum.seven, '7')
  2254. self.assertEqual(str(DumbStrEnum.seven), "don't do this")
  2255. #
  2256. class EnumMixin(Enum):
  2257. def hello(self):
  2258. print('hello from %s' % (self, ))
  2259. class HelloEnum(EnumMixin, StrEnum):
  2260. eight = '8'
  2261. self.assertEqual(HelloEnum.eight, '8')
  2262. self.assertEqual(HelloEnum.eight, str(HelloEnum.eight))
  2263. #
  2264. class GoodbyeMixin:
  2265. def goodbye(self):
  2266. print('%s wishes you a fond farewell')
  2267. class GoodbyeEnum(GoodbyeMixin, EnumMixin, StrEnum):
  2268. nine = '9'
  2269. self.assertEqual(GoodbyeEnum.nine, '9')
  2270. self.assertEqual(GoodbyeEnum.nine, str(GoodbyeEnum.nine))
  2271. #
  2272. with self.assertRaisesRegex(TypeError, '1 is not a string'):
  2273. class FirstFailedStrEnum(StrEnum):
  2274. one = 1
  2275. two = '2'
  2276. with self.assertRaisesRegex(TypeError, "2 is not a string"):
  2277. class SecondFailedStrEnum(StrEnum):
  2278. one = '1'
  2279. two = 2,
  2280. three = '3'
  2281. with self.assertRaisesRegex(TypeError, '2 is not a string'):
  2282. class ThirdFailedStrEnum(StrEnum):
  2283. one = '1'
  2284. two = 2
  2285. with self.assertRaisesRegex(TypeError, 'encoding must be a string, not %r' % (sys.getdefaultencoding, )):
  2286. class ThirdFailedStrEnum(StrEnum):
  2287. one = '1'
  2288. two = b'2', sys.getdefaultencoding
  2289. with self.assertRaisesRegex(TypeError, 'errors must be a string, not 9'):
  2290. class ThirdFailedStrEnum(StrEnum):
  2291. one = '1'
  2292. two = b'2', 'ascii', 9
  2293. def test_custom_strenum(self):
  2294. class CustomStrEnum(str, Enum):
  2295. pass
  2296. class OkayEnum(CustomStrEnum):
  2297. one = '1'
  2298. two = '2'
  2299. three = b'3', 'ascii'
  2300. four = b'4', 'latin1', 'strict'
  2301. self.assertEqual(OkayEnum.one, '1')
  2302. self.assertEqual(str(OkayEnum.one), 'OkayEnum.one')
  2303. self.assertEqual('{}'.format(OkayEnum.one), 'OkayEnum.one')
  2304. self.assertEqual(repr(OkayEnum.one), "<OkayEnum.one: '1'>")
  2305. #
  2306. class DumbMixin:
  2307. def __str__(self):
  2308. return "don't do this"
  2309. class DumbStrEnum(DumbMixin, CustomStrEnum):
  2310. five = '5'
  2311. six = '6'
  2312. seven = '7'
  2313. __str__ = DumbMixin.__str__ # needed as of 3.11
  2314. self.assertEqual(DumbStrEnum.seven, '7')
  2315. self.assertEqual(str(DumbStrEnum.seven), "don't do this")
  2316. #
  2317. class EnumMixin(Enum):
  2318. def hello(self):
  2319. print('hello from %s' % (self, ))
  2320. class HelloEnum(EnumMixin, CustomStrEnum):
  2321. eight = '8'
  2322. self.assertEqual(HelloEnum.eight, '8')
  2323. self.assertEqual(str(HelloEnum.eight), 'HelloEnum.eight')
  2324. #
  2325. class GoodbyeMixin:
  2326. def goodbye(self):
  2327. print('%s wishes you a fond farewell')
  2328. class GoodbyeEnum(GoodbyeMixin, EnumMixin, CustomStrEnum):
  2329. nine = '9'
  2330. self.assertEqual(GoodbyeEnum.nine, '9')
  2331. self.assertEqual(str(GoodbyeEnum.nine), 'GoodbyeEnum.nine')
  2332. #
  2333. class FirstFailedStrEnum(CustomStrEnum):
  2334. one = 1 # this will become '1'
  2335. two = '2'
  2336. class SecondFailedStrEnum(CustomStrEnum):
  2337. one = '1'
  2338. two = 2, # this will become '2'
  2339. three = '3'
  2340. class ThirdFailedStrEnum(CustomStrEnum):
  2341. one = '1'
  2342. two = 2 # this will become '2'
  2343. with self.assertRaisesRegex(TypeError, '.encoding. must be str, not '):
  2344. class ThirdFailedStrEnum(CustomStrEnum):
  2345. one = '1'
  2346. two = b'2', sys.getdefaultencoding
  2347. with self.assertRaisesRegex(TypeError, '.errors. must be str, not '):
  2348. class ThirdFailedStrEnum(CustomStrEnum):
  2349. one = '1'
  2350. two = b'2', 'ascii', 9
  2351. def test_missing_value_error(self):
  2352. with self.assertRaisesRegex(TypeError, "_value_ not set in __new__"):
  2353. class Combined(str, Enum):
  2354. #
  2355. def __new__(cls, value, sequence):
  2356. enum = str.__new__(cls, value)
  2357. if '(' in value:
  2358. fis_name, segment = value.split('(', 1)
  2359. segment = segment.strip(' )')
  2360. else:
  2361. fis_name = value
  2362. segment = None
  2363. enum.fis_name = fis_name
  2364. enum.segment = segment
  2365. enum.sequence = sequence
  2366. return enum
  2367. #
  2368. def __repr__(self):
  2369. return "<%s.%s>" % (self.__class__.__name__, self._name_)
  2370. #
  2371. key_type = 'An$(1,2)', 0
  2372. company_id = 'An$(3,2)', 1
  2373. code = 'An$(5,1)', 2
  2374. description = 'Bn$', 3
  2375. def test_private_variable_is_normal_attribute(self):
  2376. class Private(Enum):
  2377. __corporal = 'Radar'
  2378. __major_ = 'Hoolihan'
  2379. self.assertEqual(Private._Private__corporal, 'Radar')
  2380. self.assertEqual(Private._Private__major_, 'Hoolihan')
  2381. @unittest.skip("Accessing all values retained for performance reasons, see GH-93910")
  2382. def test_exception_for_member_from_member_access(self):
  2383. with self.assertRaisesRegex(AttributeError, "<enum .Di.> member has no attribute .NO."):
  2384. class Di(Enum):
  2385. YES = 1
  2386. NO = 0
  2387. nope = Di.YES.NO
  2388. def test_dynamic_members_with_static_methods(self):
  2389. #
  2390. foo_defines = {'FOO_CAT': 'aloof', 'BAR_DOG': 'friendly', 'FOO_HORSE': 'big'}
  2391. class Foo(Enum):
  2392. vars().update({
  2393. k: v
  2394. for k, v in foo_defines.items()
  2395. if k.startswith('FOO_')
  2396. })
  2397. def upper(self):
  2398. return self.value.upper()
  2399. self.assertEqual(list(Foo), [Foo.FOO_CAT, Foo.FOO_HORSE])
  2400. self.assertEqual(Foo.FOO_CAT.value, 'aloof')
  2401. self.assertEqual(Foo.FOO_HORSE.upper(), 'BIG')
  2402. #
  2403. with self.assertRaisesRegex(TypeError, "'FOO_CAT' already defined as 'aloof'"):
  2404. class FooBar(Enum):
  2405. vars().update({
  2406. k: v
  2407. for k, v in foo_defines.items()
  2408. if k.startswith('FOO_')
  2409. },
  2410. **{'FOO_CAT': 'small'},
  2411. )
  2412. def upper(self):
  2413. return self.value.upper()
  2414. def test_repr_with_dataclass(self):
  2415. "ensure dataclass-mixin has correct repr()"
  2416. from dataclasses import dataclass
  2417. @dataclass
  2418. class Foo:
  2419. __qualname__ = 'Foo'
  2420. a: int
  2421. class Entries(Foo, Enum):
  2422. ENTRY1 = 1
  2423. self.assertTrue(isinstance(Entries.ENTRY1, Foo))
  2424. self.assertTrue(Entries._member_type_ is Foo, Entries._member_type_)
  2425. self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value)
  2426. self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
  2427. def test_repr_with_init_data_type_mixin(self):
  2428. # non-data_type is a mixin that doesn't define __new__
  2429. class Foo:
  2430. def __init__(self, a):
  2431. self.a = a
  2432. def __repr__(self):
  2433. return f'Foo(a={self.a!r})'
  2434. class Entries(Foo, Enum):
  2435. ENTRY1 = 1
  2436. #
  2437. self.assertEqual(repr(Entries.ENTRY1), '<Entries.ENTRY1: Foo(a=1)>')
  2438. def test_repr_and_str_with_non_data_type_mixin(self):
  2439. # non-data_type is a mixin that doesn't define __new__
  2440. class Foo:
  2441. def __repr__(self):
  2442. return 'Foo'
  2443. def __str__(self):
  2444. return 'ooF'
  2445. class Entries(Foo, Enum):
  2446. ENTRY1 = 1
  2447. #
  2448. self.assertEqual(repr(Entries.ENTRY1), 'Foo')
  2449. self.assertEqual(str(Entries.ENTRY1), 'ooF')
  2450. def test_value_backup_assign(self):
  2451. # check that enum will add missing values when custom __new__ does not
  2452. class Some(Enum):
  2453. def __new__(cls, val):
  2454. return object.__new__(cls)
  2455. x = 1
  2456. y = 2
  2457. self.assertEqual(Some.x.value, 1)
  2458. self.assertEqual(Some.y.value, 2)
  2459. def test_custom_flag_bitwise(self):
  2460. class MyIntFlag(int, Flag):
  2461. ONE = 1
  2462. TWO = 2
  2463. FOUR = 4
  2464. self.assertTrue(isinstance(MyIntFlag.ONE | MyIntFlag.TWO, MyIntFlag), MyIntFlag.ONE | MyIntFlag.TWO)
  2465. self.assertTrue(isinstance(MyIntFlag.ONE | 2, MyIntFlag))
  2466. def test_int_flags_copy(self):
  2467. class MyIntFlag(IntFlag):
  2468. ONE = 1
  2469. TWO = 2
  2470. FOUR = 4
  2471. flags = MyIntFlag.ONE | MyIntFlag.TWO
  2472. copied = copy.copy(flags)
  2473. deep = copy.deepcopy(flags)
  2474. self.assertEqual(copied, flags)
  2475. self.assertEqual(deep, flags)
  2476. flags = MyIntFlag.ONE | MyIntFlag.TWO | 8
  2477. copied = copy.copy(flags)
  2478. deep = copy.deepcopy(flags)
  2479. self.assertEqual(copied, flags)
  2480. self.assertEqual(deep, flags)
  2481. self.assertEqual(copied.value, 1 | 2 | 8)
  2482. def test_namedtuple_as_value(self):
  2483. from collections import namedtuple
  2484. TTuple = namedtuple('TTuple', 'id a blist')
  2485. class NTEnum(Enum):
  2486. NONE = TTuple(0, 0, [])
  2487. A = TTuple(1, 2, [4])
  2488. B = TTuple(2, 4, [0, 1, 2])
  2489. self.assertEqual(repr(NTEnum.NONE), "<NTEnum.NONE: TTuple(id=0, a=0, blist=[])>")
  2490. self.assertEqual(NTEnum.NONE.value, TTuple(id=0, a=0, blist=[]))
  2491. self.assertEqual(
  2492. [x.value for x in NTEnum],
  2493. [TTuple(id=0, a=0, blist=[]), TTuple(id=1, a=2, blist=[4]), TTuple(id=2, a=4, blist=[0, 1, 2])],
  2494. )
  2495. def test_flag_with_custom_new(self):
  2496. class FlagFromChar(IntFlag):
  2497. def __new__(cls, c):
  2498. value = 1 << c
  2499. self = int.__new__(cls, value)
  2500. self._value_ = value
  2501. return self
  2502. #
  2503. a = ord('a')
  2504. #
  2505. self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
  2506. self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)
  2507. #
  2508. #
  2509. class FlagFromChar(Flag):
  2510. def __new__(cls, c):
  2511. value = 1 << c
  2512. self = object.__new__(cls)
  2513. self._value_ = value
  2514. return self
  2515. #
  2516. a = ord('a')
  2517. z = 1
  2518. #
  2519. self.assertEqual(FlagFromChar.a.value, 158456325028528675187087900672)
  2520. self.assertEqual((FlagFromChar.a|FlagFromChar.z).value, 158456325028528675187087900674)
  2521. #
  2522. #
  2523. class FlagFromChar(int, Flag, boundary=KEEP):
  2524. def __new__(cls, c):
  2525. value = 1 << c
  2526. self = int.__new__(cls, value)
  2527. self._value_ = value
  2528. return self
  2529. #
  2530. a = ord('a')
  2531. #
  2532. self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
  2533. self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)
  2534. class TestOrder(unittest.TestCase):
  2535. "test usage of the `_order_` attribute"
  2536. def test_same_members(self):
  2537. class Color(Enum):
  2538. _order_ = 'red green blue'
  2539. red = 1
  2540. green = 2
  2541. blue = 3
  2542. def test_same_members_with_aliases(self):
  2543. class Color(Enum):
  2544. _order_ = 'red green blue'
  2545. red = 1
  2546. green = 2
  2547. blue = 3
  2548. verde = green
  2549. def test_same_members_wrong_order(self):
  2550. with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
  2551. class Color(Enum):
  2552. _order_ = 'red green blue'
  2553. red = 1
  2554. blue = 3
  2555. green = 2
  2556. def test_order_has_extra_members(self):
  2557. with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
  2558. class Color(Enum):
  2559. _order_ = 'red green blue purple'
  2560. red = 1
  2561. green = 2
  2562. blue = 3
  2563. def test_order_has_extra_members_with_aliases(self):
  2564. with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
  2565. class Color(Enum):
  2566. _order_ = 'red green blue purple'
  2567. red = 1
  2568. green = 2
  2569. blue = 3
  2570. verde = green
  2571. def test_enum_has_extra_members(self):
  2572. with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
  2573. class Color(Enum):
  2574. _order_ = 'red green blue'
  2575. red = 1
  2576. green = 2
  2577. blue = 3
  2578. purple = 4
  2579. def test_enum_has_extra_members_with_aliases(self):
  2580. with self.assertRaisesRegex(TypeError, 'member order does not match _order_'):
  2581. class Color(Enum):
  2582. _order_ = 'red green blue'
  2583. red = 1
  2584. green = 2
  2585. blue = 3
  2586. purple = 4
  2587. verde = green
  2588. class OldTestFlag(unittest.TestCase):
  2589. """Tests of the Flags."""
  2590. class Perm(Flag):
  2591. R, W, X = 4, 2, 1
  2592. class Open(Flag):
  2593. RO = 0
  2594. WO = 1
  2595. RW = 2
  2596. AC = 3
  2597. CE = 1<<19
  2598. class Color(Flag):
  2599. BLACK = 0
  2600. RED = 1
  2601. ROJO = 1
  2602. GREEN = 2
  2603. BLUE = 4
  2604. PURPLE = RED|BLUE
  2605. WHITE = RED|GREEN|BLUE
  2606. BLANCO = RED|GREEN|BLUE
  2607. def test_or(self):
  2608. Perm = self.Perm
  2609. for i in Perm:
  2610. for j in Perm:
  2611. self.assertEqual((i | j), Perm(i.value | j.value))
  2612. self.assertEqual((i | j).value, i.value | j.value)
  2613. self.assertIs(type(i | j), Perm)
  2614. for i in Perm:
  2615. self.assertIs(i | i, i)
  2616. Open = self.Open
  2617. self.assertIs(Open.RO | Open.CE, Open.CE)
  2618. def test_and(self):
  2619. Perm = self.Perm
  2620. RW = Perm.R | Perm.W
  2621. RX = Perm.R | Perm.X
  2622. WX = Perm.W | Perm.X
  2623. RWX = Perm.R | Perm.W | Perm.X
  2624. values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
  2625. for i in values:
  2626. for j in values:
  2627. self.assertEqual((i & j).value, i.value & j.value)
  2628. self.assertIs(type(i & j), Perm)
  2629. for i in Perm:
  2630. self.assertIs(i & i, i)
  2631. self.assertIs(i & RWX, i)
  2632. self.assertIs(RWX & i, i)
  2633. Open = self.Open
  2634. self.assertIs(Open.RO & Open.CE, Open.RO)
  2635. def test_xor(self):
  2636. Perm = self.Perm
  2637. for i in Perm:
  2638. for j in Perm:
  2639. self.assertEqual((i ^ j).value, i.value ^ j.value)
  2640. self.assertIs(type(i ^ j), Perm)
  2641. for i in Perm:
  2642. self.assertIs(i ^ Perm(0), i)
  2643. self.assertIs(Perm(0) ^ i, i)
  2644. Open = self.Open
  2645. self.assertIs(Open.RO ^ Open.CE, Open.CE)
  2646. self.assertIs(Open.CE ^ Open.CE, Open.RO)
  2647. def test_invert(self):
  2648. Perm = self.Perm
  2649. RW = Perm.R | Perm.W
  2650. RX = Perm.R | Perm.X
  2651. WX = Perm.W | Perm.X
  2652. RWX = Perm.R | Perm.W | Perm.X
  2653. values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
  2654. for i in values:
  2655. self.assertIs(type(~i), Perm)
  2656. self.assertEqual(~~i, i)
  2657. for i in Perm:
  2658. self.assertIs(~~i, i)
  2659. Open = self.Open
  2660. self.assertIs(Open.WO & ~Open.WO, Open.RO)
  2661. self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
  2662. def test_bool(self):
  2663. Perm = self.Perm
  2664. for f in Perm:
  2665. self.assertTrue(f)
  2666. Open = self.Open
  2667. for f in Open:
  2668. self.assertEqual(bool(f.value), bool(f))
  2669. def test_boundary(self):
  2670. self.assertIs(enum.Flag._boundary_, CONFORM)
  2671. class Iron(Flag, boundary=STRICT):
  2672. ONE = 1
  2673. TWO = 2
  2674. EIGHT = 8
  2675. self.assertIs(Iron._boundary_, STRICT)
  2676. #
  2677. class Water(Flag, boundary=CONFORM):
  2678. ONE = 1
  2679. TWO = 2
  2680. EIGHT = 8
  2681. self.assertIs(Water._boundary_, CONFORM)
  2682. #
  2683. class Space(Flag, boundary=EJECT):
  2684. ONE = 1
  2685. TWO = 2
  2686. EIGHT = 8
  2687. self.assertIs(Space._boundary_, EJECT)
  2688. #
  2689. class Bizarre(Flag, boundary=KEEP):
  2690. b = 3
  2691. c = 4
  2692. d = 6
  2693. #
  2694. self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7)
  2695. #
  2696. self.assertIs(Water(7), Water.ONE|Water.TWO)
  2697. self.assertIs(Water(~9), Water.TWO)
  2698. #
  2699. self.assertEqual(Space(7), 7)
  2700. self.assertTrue(type(Space(7)) is int)
  2701. #
  2702. self.assertEqual(list(Bizarre), [Bizarre.c])
  2703. self.assertIs(Bizarre(3), Bizarre.b)
  2704. self.assertIs(Bizarre(6), Bizarre.d)
  2705. def test_iter(self):
  2706. Color = self.Color
  2707. Open = self.Open
  2708. self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
  2709. self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
  2710. def test_programatic_function_string(self):
  2711. Perm = Flag('Perm', 'R W X')
  2712. lst = list(Perm)
  2713. self.assertEqual(len(lst), len(Perm))
  2714. self.assertEqual(len(Perm), 3, Perm)
  2715. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  2716. for i, n in enumerate('R W X'.split()):
  2717. v = 1<<i
  2718. e = Perm(v)
  2719. self.assertEqual(e.value, v)
  2720. self.assertEqual(type(e.value), int)
  2721. self.assertEqual(e.name, n)
  2722. self.assertIn(e, Perm)
  2723. self.assertIs(type(e), Perm)
  2724. def test_programatic_function_string_with_start(self):
  2725. Perm = Flag('Perm', 'R W X', start=8)
  2726. lst = list(Perm)
  2727. self.assertEqual(len(lst), len(Perm))
  2728. self.assertEqual(len(Perm), 3, Perm)
  2729. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  2730. for i, n in enumerate('R W X'.split()):
  2731. v = 8<<i
  2732. e = Perm(v)
  2733. self.assertEqual(e.value, v)
  2734. self.assertEqual(type(e.value), int)
  2735. self.assertEqual(e.name, n)
  2736. self.assertIn(e, Perm)
  2737. self.assertIs(type(e), Perm)
  2738. def test_programatic_function_string_list(self):
  2739. Perm = Flag('Perm', ['R', 'W', 'X'])
  2740. lst = list(Perm)
  2741. self.assertEqual(len(lst), len(Perm))
  2742. self.assertEqual(len(Perm), 3, Perm)
  2743. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  2744. for i, n in enumerate('R W X'.split()):
  2745. v = 1<<i
  2746. e = Perm(v)
  2747. self.assertEqual(e.value, v)
  2748. self.assertEqual(type(e.value), int)
  2749. self.assertEqual(e.name, n)
  2750. self.assertIn(e, Perm)
  2751. self.assertIs(type(e), Perm)
  2752. def test_programatic_function_iterable(self):
  2753. Perm = Flag('Perm', (('R', 2), ('W', 8), ('X', 32)))
  2754. lst = list(Perm)
  2755. self.assertEqual(len(lst), len(Perm))
  2756. self.assertEqual(len(Perm), 3, Perm)
  2757. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  2758. for i, n in enumerate('R W X'.split()):
  2759. v = 1<<(2*i+1)
  2760. e = Perm(v)
  2761. self.assertEqual(e.value, v)
  2762. self.assertEqual(type(e.value), int)
  2763. self.assertEqual(e.name, n)
  2764. self.assertIn(e, Perm)
  2765. self.assertIs(type(e), Perm)
  2766. def test_programatic_function_from_dict(self):
  2767. Perm = Flag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
  2768. lst = list(Perm)
  2769. self.assertEqual(len(lst), len(Perm))
  2770. self.assertEqual(len(Perm), 3, Perm)
  2771. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  2772. for i, n in enumerate('R W X'.split()):
  2773. v = 1<<(2*i+1)
  2774. e = Perm(v)
  2775. self.assertEqual(e.value, v)
  2776. self.assertEqual(type(e.value), int)
  2777. self.assertEqual(e.name, n)
  2778. self.assertIn(e, Perm)
  2779. self.assertIs(type(e), Perm)
  2780. def test_pickle(self):
  2781. if isinstance(FlagStooges, Exception):
  2782. raise FlagStooges
  2783. test_pickle_dump_load(self.assertIs, FlagStooges.CURLY)
  2784. test_pickle_dump_load(self.assertEqual,
  2785. FlagStooges.CURLY|FlagStooges.MOE)
  2786. test_pickle_dump_load(self.assertEqual,
  2787. FlagStooges.CURLY&~FlagStooges.CURLY)
  2788. test_pickle_dump_load(self.assertIs, FlagStooges)
  2789. test_pickle_dump_load(self.assertIs, FlagStoogesWithZero.CURLY)
  2790. test_pickle_dump_load(self.assertEqual,
  2791. FlagStoogesWithZero.CURLY|FlagStoogesWithZero.MOE)
  2792. test_pickle_dump_load(self.assertIs, FlagStoogesWithZero.NOFLAG)
  2793. test_pickle_dump_load(self.assertIs, IntFlagStooges.CURLY)
  2794. test_pickle_dump_load(self.assertEqual,
  2795. IntFlagStooges.CURLY|IntFlagStooges.MOE)
  2796. test_pickle_dump_load(self.assertEqual,
  2797. IntFlagStooges.CURLY|IntFlagStooges.MOE|0x30)
  2798. test_pickle_dump_load(self.assertEqual, IntFlagStooges(0))
  2799. test_pickle_dump_load(self.assertEqual, IntFlagStooges(0x30))
  2800. test_pickle_dump_load(self.assertIs, IntFlagStooges)
  2801. test_pickle_dump_load(self.assertIs, IntFlagStoogesWithZero.CURLY)
  2802. test_pickle_dump_load(self.assertEqual,
  2803. IntFlagStoogesWithZero.CURLY|IntFlagStoogesWithZero.MOE)
  2804. test_pickle_dump_load(self.assertIs, IntFlagStoogesWithZero.NOFLAG)
  2805. @unittest.skipIf(
  2806. python_version >= (3, 12),
  2807. '__contains__ now returns True/False for all inputs',
  2808. )
  2809. def test_contains_er(self):
  2810. Open = self.Open
  2811. Color = self.Color
  2812. self.assertFalse(Color.BLACK in Open)
  2813. self.assertFalse(Open.RO in Color)
  2814. with self.assertRaises(TypeError):
  2815. with self.assertWarns(DeprecationWarning):
  2816. 'BLACK' in Color
  2817. with self.assertRaises(TypeError):
  2818. with self.assertWarns(DeprecationWarning):
  2819. 'RO' in Open
  2820. with self.assertRaises(TypeError):
  2821. with self.assertWarns(DeprecationWarning):
  2822. 1 in Color
  2823. with self.assertRaises(TypeError):
  2824. with self.assertWarns(DeprecationWarning):
  2825. 1 in Open
  2826. @unittest.skipIf(
  2827. python_version < (3, 12),
  2828. '__contains__ only works with enum memmbers before 3.12',
  2829. )
  2830. def test_contains_tf(self):
  2831. Open = self.Open
  2832. Color = self.Color
  2833. self.assertFalse(Color.BLACK in Open)
  2834. self.assertFalse(Open.RO in Color)
  2835. self.assertFalse('BLACK' in Color)
  2836. self.assertFalse('RO' in Open)
  2837. self.assertTrue(1 in Color)
  2838. self.assertTrue(1 in Open)
  2839. def test_member_contains(self):
  2840. Perm = self.Perm
  2841. R, W, X = Perm
  2842. RW = R | W
  2843. RX = R | X
  2844. WX = W | X
  2845. RWX = R | W | X
  2846. self.assertTrue(R in RW)
  2847. self.assertTrue(R in RX)
  2848. self.assertTrue(R in RWX)
  2849. self.assertTrue(W in RW)
  2850. self.assertTrue(W in WX)
  2851. self.assertTrue(W in RWX)
  2852. self.assertTrue(X in RX)
  2853. self.assertTrue(X in WX)
  2854. self.assertTrue(X in RWX)
  2855. self.assertFalse(R in WX)
  2856. self.assertFalse(W in RX)
  2857. self.assertFalse(X in RW)
  2858. def test_member_iter(self):
  2859. Color = self.Color
  2860. self.assertEqual(list(Color.BLACK), [])
  2861. self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
  2862. self.assertEqual(list(Color.BLUE), [Color.BLUE])
  2863. self.assertEqual(list(Color.GREEN), [Color.GREEN])
  2864. self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
  2865. self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
  2866. def test_member_length(self):
  2867. self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
  2868. self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
  2869. self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
  2870. self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
  2871. def test_number_reset_and_order_cleanup(self):
  2872. class Confused(Flag):
  2873. _order_ = 'ONE TWO FOUR DOS EIGHT SIXTEEN'
  2874. ONE = auto()
  2875. TWO = auto()
  2876. FOUR = auto()
  2877. DOS = 2
  2878. EIGHT = auto()
  2879. SIXTEEN = auto()
  2880. self.assertEqual(
  2881. list(Confused),
  2882. [Confused.ONE, Confused.TWO, Confused.FOUR, Confused.EIGHT, Confused.SIXTEEN])
  2883. self.assertIs(Confused.TWO, Confused.DOS)
  2884. self.assertEqual(Confused.DOS._value_, 2)
  2885. self.assertEqual(Confused.EIGHT._value_, 8)
  2886. self.assertEqual(Confused.SIXTEEN._value_, 16)
  2887. def test_aliases(self):
  2888. Color = self.Color
  2889. self.assertEqual(Color(1).name, 'RED')
  2890. self.assertEqual(Color['ROJO'].name, 'RED')
  2891. self.assertEqual(Color(7).name, 'WHITE')
  2892. self.assertEqual(Color['BLANCO'].name, 'WHITE')
  2893. self.assertIs(Color.BLANCO, Color.WHITE)
  2894. Open = self.Open
  2895. self.assertIs(Open['AC'], Open.AC)
  2896. def test_auto_number(self):
  2897. class Color(Flag):
  2898. red = auto()
  2899. blue = auto()
  2900. green = auto()
  2901. self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
  2902. self.assertEqual(Color.red.value, 1)
  2903. self.assertEqual(Color.blue.value, 2)
  2904. self.assertEqual(Color.green.value, 4)
  2905. def test_auto_number_garbage(self):
  2906. with self.assertRaisesRegex(TypeError, 'invalid flag value .not an int.'):
  2907. class Color(Flag):
  2908. red = 'not an int'
  2909. blue = auto()
  2910. def test_duplicate_auto(self):
  2911. class Dupes(Enum):
  2912. first = primero = auto()
  2913. second = auto()
  2914. third = auto()
  2915. self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
  2916. def test_multiple_mixin(self):
  2917. class AllMixin:
  2918. @classproperty
  2919. def ALL(cls):
  2920. members = list(cls)
  2921. all_value = None
  2922. if members:
  2923. all_value = members[0]
  2924. for member in members[1:]:
  2925. all_value |= member
  2926. cls.ALL = all_value
  2927. return all_value
  2928. class StrMixin:
  2929. def __str__(self):
  2930. return self._name_.lower()
  2931. class Color(AllMixin, Flag):
  2932. RED = auto()
  2933. GREEN = auto()
  2934. BLUE = auto()
  2935. self.assertEqual(Color.RED.value, 1)
  2936. self.assertEqual(Color.GREEN.value, 2)
  2937. self.assertEqual(Color.BLUE.value, 4)
  2938. self.assertEqual(Color.ALL.value, 7)
  2939. self.assertEqual(str(Color.BLUE), 'Color.BLUE')
  2940. class Color(AllMixin, StrMixin, Flag):
  2941. RED = auto()
  2942. GREEN = auto()
  2943. BLUE = auto()
  2944. __str__ = StrMixin.__str__
  2945. self.assertEqual(Color.RED.value, 1)
  2946. self.assertEqual(Color.GREEN.value, 2)
  2947. self.assertEqual(Color.BLUE.value, 4)
  2948. self.assertEqual(Color.ALL.value, 7)
  2949. self.assertEqual(str(Color.BLUE), 'blue')
  2950. class Color(StrMixin, AllMixin, Flag):
  2951. RED = auto()
  2952. GREEN = auto()
  2953. BLUE = auto()
  2954. __str__ = StrMixin.__str__
  2955. self.assertEqual(Color.RED.value, 1)
  2956. self.assertEqual(Color.GREEN.value, 2)
  2957. self.assertEqual(Color.BLUE.value, 4)
  2958. self.assertEqual(Color.ALL.value, 7)
  2959. self.assertEqual(str(Color.BLUE), 'blue')
  2960. @threading_helper.reap_threads
  2961. @threading_helper.requires_working_threading()
  2962. def test_unique_composite(self):
  2963. # override __eq__ to be identity only
  2964. class TestFlag(Flag):
  2965. one = auto()
  2966. two = auto()
  2967. three = auto()
  2968. four = auto()
  2969. five = auto()
  2970. six = auto()
  2971. seven = auto()
  2972. eight = auto()
  2973. def __eq__(self, other):
  2974. return self is other
  2975. def __hash__(self):
  2976. return hash(self._value_)
  2977. # have multiple threads competing to complete the composite members
  2978. seen = set()
  2979. failed = False
  2980. def cycle_enum():
  2981. nonlocal failed
  2982. try:
  2983. for i in range(256):
  2984. seen.add(TestFlag(i))
  2985. except Exception:
  2986. failed = True
  2987. threads = [
  2988. threading.Thread(target=cycle_enum)
  2989. for _ in range(8)
  2990. ]
  2991. with threading_helper.start_threads(threads):
  2992. pass
  2993. # check that only 248 members were created
  2994. self.assertFalse(
  2995. failed,
  2996. 'at least one thread failed while creating composite members')
  2997. self.assertEqual(256, len(seen), 'too many composite members created')
  2998. def test_init_subclass(self):
  2999. class MyEnum(Flag):
  3000. def __init_subclass__(cls, **kwds):
  3001. super().__init_subclass__(**kwds)
  3002. self.assertFalse(cls.__dict__.get('_test', False))
  3003. cls._test1 = 'MyEnum'
  3004. #
  3005. class TheirEnum(MyEnum):
  3006. def __init_subclass__(cls, **kwds):
  3007. super(TheirEnum, cls).__init_subclass__(**kwds)
  3008. cls._test2 = 'TheirEnum'
  3009. class WhoseEnum(TheirEnum):
  3010. def __init_subclass__(cls, **kwds):
  3011. pass
  3012. class NoEnum(WhoseEnum):
  3013. ONE = 1
  3014. self.assertEqual(TheirEnum.__dict__['_test1'], 'MyEnum')
  3015. self.assertEqual(WhoseEnum.__dict__['_test1'], 'MyEnum')
  3016. self.assertEqual(WhoseEnum.__dict__['_test2'], 'TheirEnum')
  3017. self.assertFalse(NoEnum.__dict__.get('_test1', False))
  3018. self.assertFalse(NoEnum.__dict__.get('_test2', False))
  3019. #
  3020. class OurEnum(MyEnum):
  3021. def __init_subclass__(cls, **kwds):
  3022. cls._test2 = 'OurEnum'
  3023. class WhereEnum(OurEnum):
  3024. def __init_subclass__(cls, **kwds):
  3025. pass
  3026. class NeverEnum(WhereEnum):
  3027. ONE = 1
  3028. self.assertEqual(OurEnum.__dict__['_test1'], 'MyEnum')
  3029. self.assertFalse(WhereEnum.__dict__.get('_test1', False))
  3030. self.assertEqual(WhereEnum.__dict__['_test2'], 'OurEnum')
  3031. self.assertFalse(NeverEnum.__dict__.get('_test1', False))
  3032. self.assertFalse(NeverEnum.__dict__.get('_test2', False))
  3033. class OldTestIntFlag(unittest.TestCase):
  3034. """Tests of the IntFlags."""
  3035. class Perm(IntFlag):
  3036. R = 1 << 2
  3037. W = 1 << 1
  3038. X = 1 << 0
  3039. class Open(IntFlag):
  3040. RO = 0
  3041. WO = 1
  3042. RW = 2
  3043. AC = 3
  3044. CE = 1<<19
  3045. class Color(IntFlag):
  3046. BLACK = 0
  3047. RED = 1
  3048. ROJO = 1
  3049. GREEN = 2
  3050. BLUE = 4
  3051. PURPLE = RED|BLUE
  3052. WHITE = RED|GREEN|BLUE
  3053. BLANCO = RED|GREEN|BLUE
  3054. class Skip(IntFlag):
  3055. FIRST = 1
  3056. SECOND = 2
  3057. EIGHTH = 8
  3058. def test_type(self):
  3059. Perm = self.Perm
  3060. self.assertTrue(Perm._member_type_ is int)
  3061. Open = self.Open
  3062. for f in Perm:
  3063. self.assertTrue(isinstance(f, Perm))
  3064. self.assertEqual(f, f.value)
  3065. self.assertTrue(isinstance(Perm.W | Perm.X, Perm))
  3066. self.assertEqual(Perm.W | Perm.X, 3)
  3067. for f in Open:
  3068. self.assertTrue(isinstance(f, Open))
  3069. self.assertEqual(f, f.value)
  3070. self.assertTrue(isinstance(Open.WO | Open.RW, Open))
  3071. self.assertEqual(Open.WO | Open.RW, 3)
  3072. def test_global_repr_keep(self):
  3073. self.assertEqual(
  3074. repr(HeadlightsK(0)),
  3075. '%s.OFF_K' % SHORT_MODULE,
  3076. )
  3077. self.assertEqual(
  3078. repr(HeadlightsK(2**0 + 2**2 + 2**3)),
  3079. '%(m)s.LOW_BEAM_K|%(m)s.FOG_K|8' % {'m': SHORT_MODULE},
  3080. )
  3081. self.assertEqual(
  3082. repr(HeadlightsK(2**3)),
  3083. '%(m)s.HeadlightsK(8)' % {'m': SHORT_MODULE},
  3084. )
  3085. def test_global_repr_conform1(self):
  3086. self.assertEqual(
  3087. repr(HeadlightsC(0)),
  3088. '%s.OFF_C' % SHORT_MODULE,
  3089. )
  3090. self.assertEqual(
  3091. repr(HeadlightsC(2**0 + 2**2 + 2**3)),
  3092. '%(m)s.LOW_BEAM_C|%(m)s.FOG_C' % {'m': SHORT_MODULE},
  3093. )
  3094. self.assertEqual(
  3095. repr(HeadlightsC(2**3)),
  3096. '%(m)s.OFF_C' % {'m': SHORT_MODULE},
  3097. )
  3098. def test_global_enum_str(self):
  3099. self.assertEqual(str(NoName.ONE & NoName.TWO), 'NoName(0)')
  3100. self.assertEqual(str(NoName(0)), 'NoName(0)')
  3101. def test_format(self):
  3102. Perm = self.Perm
  3103. self.assertEqual(format(Perm.R, ''), '4')
  3104. self.assertEqual(format(Perm.R | Perm.X, ''), '5')
  3105. #
  3106. class NewPerm(IntFlag):
  3107. R = 1 << 2
  3108. W = 1 << 1
  3109. X = 1 << 0
  3110. def __str__(self):
  3111. return self._name_
  3112. self.assertEqual(format(NewPerm.R, ''), 'R')
  3113. self.assertEqual(format(NewPerm.R | Perm.X, ''), 'R|X')
  3114. def test_or(self):
  3115. Perm = self.Perm
  3116. for i in Perm:
  3117. for j in Perm:
  3118. self.assertEqual(i | j, i.value | j.value)
  3119. self.assertEqual((i | j).value, i.value | j.value)
  3120. self.assertIs(type(i | j), Perm)
  3121. for j in range(8):
  3122. self.assertEqual(i | j, i.value | j)
  3123. self.assertEqual((i | j).value, i.value | j)
  3124. self.assertIs(type(i | j), Perm)
  3125. self.assertEqual(j | i, j | i.value)
  3126. self.assertEqual((j | i).value, j | i.value)
  3127. self.assertIs(type(j | i), Perm)
  3128. for i in Perm:
  3129. self.assertIs(i | i, i)
  3130. self.assertIs(i | 0, i)
  3131. self.assertIs(0 | i, i)
  3132. Open = self.Open
  3133. self.assertIs(Open.RO | Open.CE, Open.CE)
  3134. def test_and(self):
  3135. Perm = self.Perm
  3136. RW = Perm.R | Perm.W
  3137. RX = Perm.R | Perm.X
  3138. WX = Perm.W | Perm.X
  3139. RWX = Perm.R | Perm.W | Perm.X
  3140. values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
  3141. for i in values:
  3142. for j in values:
  3143. self.assertEqual(i & j, i.value & j.value, 'i is %r, j is %r' % (i, j))
  3144. self.assertEqual((i & j).value, i.value & j.value, 'i is %r, j is %r' % (i, j))
  3145. self.assertIs(type(i & j), Perm, 'i is %r, j is %r' % (i, j))
  3146. for j in range(8):
  3147. self.assertEqual(i & j, i.value & j)
  3148. self.assertEqual((i & j).value, i.value & j)
  3149. self.assertIs(type(i & j), Perm)
  3150. self.assertEqual(j & i, j & i.value)
  3151. self.assertEqual((j & i).value, j & i.value)
  3152. self.assertIs(type(j & i), Perm)
  3153. for i in Perm:
  3154. self.assertIs(i & i, i)
  3155. self.assertIs(i & 7, i)
  3156. self.assertIs(7 & i, i)
  3157. Open = self.Open
  3158. self.assertIs(Open.RO & Open.CE, Open.RO)
  3159. def test_xor(self):
  3160. Perm = self.Perm
  3161. for i in Perm:
  3162. for j in Perm:
  3163. self.assertEqual(i ^ j, i.value ^ j.value)
  3164. self.assertEqual((i ^ j).value, i.value ^ j.value)
  3165. self.assertIs(type(i ^ j), Perm)
  3166. for j in range(8):
  3167. self.assertEqual(i ^ j, i.value ^ j)
  3168. self.assertEqual((i ^ j).value, i.value ^ j)
  3169. self.assertIs(type(i ^ j), Perm)
  3170. self.assertEqual(j ^ i, j ^ i.value)
  3171. self.assertEqual((j ^ i).value, j ^ i.value)
  3172. self.assertIs(type(j ^ i), Perm)
  3173. for i in Perm:
  3174. self.assertIs(i ^ 0, i)
  3175. self.assertIs(0 ^ i, i)
  3176. Open = self.Open
  3177. self.assertIs(Open.RO ^ Open.CE, Open.CE)
  3178. self.assertIs(Open.CE ^ Open.CE, Open.RO)
  3179. def test_invert(self):
  3180. Perm = self.Perm
  3181. RW = Perm.R | Perm.W
  3182. RX = Perm.R | Perm.X
  3183. WX = Perm.W | Perm.X
  3184. RWX = Perm.R | Perm.W | Perm.X
  3185. values = list(Perm) + [RW, RX, WX, RWX, Perm(0)]
  3186. for i in values:
  3187. self.assertEqual(~i, (~i).value)
  3188. self.assertIs(type(~i), Perm)
  3189. self.assertEqual(~~i, i)
  3190. for i in Perm:
  3191. self.assertIs(~~i, i)
  3192. Open = self.Open
  3193. self.assertIs(Open.WO & ~Open.WO, Open.RO)
  3194. self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE)
  3195. def test_boundary(self):
  3196. self.assertIs(enum.IntFlag._boundary_, KEEP)
  3197. class Simple(IntFlag, boundary=KEEP):
  3198. SINGLE = 1
  3199. #
  3200. class Iron(IntFlag, boundary=STRICT):
  3201. ONE = 1
  3202. TWO = 2
  3203. EIGHT = 8
  3204. self.assertIs(Iron._boundary_, STRICT)
  3205. #
  3206. class Water(IntFlag, boundary=CONFORM):
  3207. ONE = 1
  3208. TWO = 2
  3209. EIGHT = 8
  3210. self.assertIs(Water._boundary_, CONFORM)
  3211. #
  3212. class Space(IntFlag, boundary=EJECT):
  3213. ONE = 1
  3214. TWO = 2
  3215. EIGHT = 8
  3216. self.assertIs(Space._boundary_, EJECT)
  3217. #
  3218. class Bizarre(IntFlag, boundary=KEEP):
  3219. b = 3
  3220. c = 4
  3221. d = 6
  3222. #
  3223. self.assertRaisesRegex(ValueError, 'invalid value 5', Iron, 5)
  3224. #
  3225. self.assertIs(Water(7), Water.ONE|Water.TWO)
  3226. self.assertIs(Water(~9), Water.TWO)
  3227. #
  3228. self.assertEqual(Space(7), 7)
  3229. self.assertTrue(type(Space(7)) is int)
  3230. #
  3231. self.assertEqual(list(Bizarre), [Bizarre.c])
  3232. self.assertIs(Bizarre(3), Bizarre.b)
  3233. self.assertIs(Bizarre(6), Bizarre.d)
  3234. #
  3235. simple = Simple.SINGLE | Iron.TWO
  3236. self.assertEqual(simple, 3)
  3237. self.assertIsInstance(simple, Simple)
  3238. self.assertEqual(repr(simple), '<Simple.SINGLE|<Iron.TWO: 2>: 3>')
  3239. self.assertEqual(str(simple), '3')
  3240. def test_iter(self):
  3241. Color = self.Color
  3242. Open = self.Open
  3243. self.assertEqual(list(Color), [Color.RED, Color.GREEN, Color.BLUE])
  3244. self.assertEqual(list(Open), [Open.WO, Open.RW, Open.CE])
  3245. def test_programatic_function_string(self):
  3246. Perm = IntFlag('Perm', 'R W X')
  3247. lst = list(Perm)
  3248. self.assertEqual(len(lst), len(Perm))
  3249. self.assertEqual(len(Perm), 3, Perm)
  3250. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  3251. for i, n in enumerate('R W X'.split()):
  3252. v = 1<<i
  3253. e = Perm(v)
  3254. self.assertEqual(e.value, v)
  3255. self.assertEqual(type(e.value), int)
  3256. self.assertEqual(e, v)
  3257. self.assertEqual(e.name, n)
  3258. self.assertIn(e, Perm)
  3259. self.assertIs(type(e), Perm)
  3260. def test_programatic_function_string_with_start(self):
  3261. Perm = IntFlag('Perm', 'R W X', start=8)
  3262. lst = list(Perm)
  3263. self.assertEqual(len(lst), len(Perm))
  3264. self.assertEqual(len(Perm), 3, Perm)
  3265. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  3266. for i, n in enumerate('R W X'.split()):
  3267. v = 8<<i
  3268. e = Perm(v)
  3269. self.assertEqual(e.value, v)
  3270. self.assertEqual(type(e.value), int)
  3271. self.assertEqual(e, v)
  3272. self.assertEqual(e.name, n)
  3273. self.assertIn(e, Perm)
  3274. self.assertIs(type(e), Perm)
  3275. def test_programatic_function_string_list(self):
  3276. Perm = IntFlag('Perm', ['R', 'W', 'X'])
  3277. lst = list(Perm)
  3278. self.assertEqual(len(lst), len(Perm))
  3279. self.assertEqual(len(Perm), 3, Perm)
  3280. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  3281. for i, n in enumerate('R W X'.split()):
  3282. v = 1<<i
  3283. e = Perm(v)
  3284. self.assertEqual(e.value, v)
  3285. self.assertEqual(type(e.value), int)
  3286. self.assertEqual(e, v)
  3287. self.assertEqual(e.name, n)
  3288. self.assertIn(e, Perm)
  3289. self.assertIs(type(e), Perm)
  3290. def test_programatic_function_iterable(self):
  3291. Perm = IntFlag('Perm', (('R', 2), ('W', 8), ('X', 32)))
  3292. lst = list(Perm)
  3293. self.assertEqual(len(lst), len(Perm))
  3294. self.assertEqual(len(Perm), 3, Perm)
  3295. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  3296. for i, n in enumerate('R W X'.split()):
  3297. v = 1<<(2*i+1)
  3298. e = Perm(v)
  3299. self.assertEqual(e.value, v)
  3300. self.assertEqual(type(e.value), int)
  3301. self.assertEqual(e, v)
  3302. self.assertEqual(e.name, n)
  3303. self.assertIn(e, Perm)
  3304. self.assertIs(type(e), Perm)
  3305. def test_programatic_function_from_dict(self):
  3306. Perm = IntFlag('Perm', OrderedDict((('R', 2), ('W', 8), ('X', 32))))
  3307. lst = list(Perm)
  3308. self.assertEqual(len(lst), len(Perm))
  3309. self.assertEqual(len(Perm), 3, Perm)
  3310. self.assertEqual(lst, [Perm.R, Perm.W, Perm.X])
  3311. for i, n in enumerate('R W X'.split()):
  3312. v = 1<<(2*i+1)
  3313. e = Perm(v)
  3314. self.assertEqual(e.value, v)
  3315. self.assertEqual(type(e.value), int)
  3316. self.assertEqual(e, v)
  3317. self.assertEqual(e.name, n)
  3318. self.assertIn(e, Perm)
  3319. self.assertIs(type(e), Perm)
  3320. def test_programatic_function_from_empty_list(self):
  3321. Perm = enum.IntFlag('Perm', [])
  3322. lst = list(Perm)
  3323. self.assertEqual(len(lst), len(Perm))
  3324. self.assertEqual(len(Perm), 0, Perm)
  3325. Thing = enum.Enum('Thing', [])
  3326. lst = list(Thing)
  3327. self.assertEqual(len(lst), len(Thing))
  3328. self.assertEqual(len(Thing), 0, Thing)
  3329. def test_programatic_function_from_empty_tuple(self):
  3330. Perm = enum.IntFlag('Perm', ())
  3331. lst = list(Perm)
  3332. self.assertEqual(len(lst), len(Perm))
  3333. self.assertEqual(len(Perm), 0, Perm)
  3334. Thing = enum.Enum('Thing', ())
  3335. self.assertEqual(len(lst), len(Thing))
  3336. self.assertEqual(len(Thing), 0, Thing)
  3337. @unittest.skipIf(
  3338. python_version >= (3, 12),
  3339. '__contains__ now returns True/False for all inputs',
  3340. )
  3341. def test_contains_er(self):
  3342. Open = self.Open
  3343. Color = self.Color
  3344. self.assertTrue(Color.GREEN in Color)
  3345. self.assertTrue(Open.RW in Open)
  3346. self.assertFalse(Color.GREEN in Open)
  3347. self.assertFalse(Open.RW in Color)
  3348. with self.assertRaises(TypeError):
  3349. with self.assertWarns(DeprecationWarning):
  3350. 'GREEN' in Color
  3351. with self.assertRaises(TypeError):
  3352. with self.assertWarns(DeprecationWarning):
  3353. 'RW' in Open
  3354. with self.assertRaises(TypeError):
  3355. with self.assertWarns(DeprecationWarning):
  3356. 2 in Color
  3357. with self.assertRaises(TypeError):
  3358. with self.assertWarns(DeprecationWarning):
  3359. 2 in Open
  3360. @unittest.skipIf(
  3361. python_version < (3, 12),
  3362. '__contains__ only works with enum memmbers before 3.12',
  3363. )
  3364. def test_contains_tf(self):
  3365. Open = self.Open
  3366. Color = self.Color
  3367. self.assertTrue(Color.GREEN in Color)
  3368. self.assertTrue(Open.RW in Open)
  3369. self.assertTrue(Color.GREEN in Open)
  3370. self.assertTrue(Open.RW in Color)
  3371. self.assertFalse('GREEN' in Color)
  3372. self.assertFalse('RW' in Open)
  3373. self.assertTrue(2 in Color)
  3374. self.assertTrue(2 in Open)
  3375. def test_member_contains(self):
  3376. Perm = self.Perm
  3377. R, W, X = Perm
  3378. RW = R | W
  3379. RX = R | X
  3380. WX = W | X
  3381. RWX = R | W | X
  3382. self.assertTrue(R in RW)
  3383. self.assertTrue(R in RX)
  3384. self.assertTrue(R in RWX)
  3385. self.assertTrue(W in RW)
  3386. self.assertTrue(W in WX)
  3387. self.assertTrue(W in RWX)
  3388. self.assertTrue(X in RX)
  3389. self.assertTrue(X in WX)
  3390. self.assertTrue(X in RWX)
  3391. self.assertFalse(R in WX)
  3392. self.assertFalse(W in RX)
  3393. self.assertFalse(X in RW)
  3394. with self.assertRaises(TypeError):
  3395. self.assertFalse('test' in RW)
  3396. def test_member_iter(self):
  3397. Color = self.Color
  3398. self.assertEqual(list(Color.BLACK), [])
  3399. self.assertEqual(list(Color.PURPLE), [Color.RED, Color.BLUE])
  3400. self.assertEqual(list(Color.BLUE), [Color.BLUE])
  3401. self.assertEqual(list(Color.GREEN), [Color.GREEN])
  3402. self.assertEqual(list(Color.WHITE), [Color.RED, Color.GREEN, Color.BLUE])
  3403. def test_member_length(self):
  3404. self.assertEqual(self.Color.__len__(self.Color.BLACK), 0)
  3405. self.assertEqual(self.Color.__len__(self.Color.GREEN), 1)
  3406. self.assertEqual(self.Color.__len__(self.Color.PURPLE), 2)
  3407. self.assertEqual(self.Color.__len__(self.Color.BLANCO), 3)
  3408. def test_aliases(self):
  3409. Color = self.Color
  3410. self.assertEqual(Color(1).name, 'RED')
  3411. self.assertEqual(Color['ROJO'].name, 'RED')
  3412. self.assertEqual(Color(7).name, 'WHITE')
  3413. self.assertEqual(Color['BLANCO'].name, 'WHITE')
  3414. self.assertIs(Color.BLANCO, Color.WHITE)
  3415. Open = self.Open
  3416. self.assertIs(Open['AC'], Open.AC)
  3417. def test_bool(self):
  3418. Perm = self.Perm
  3419. for f in Perm:
  3420. self.assertTrue(f)
  3421. Open = self.Open
  3422. for f in Open:
  3423. self.assertEqual(bool(f.value), bool(f))
  3424. def test_multiple_mixin(self):
  3425. class AllMixin:
  3426. @classproperty
  3427. def ALL(cls):
  3428. members = list(cls)
  3429. all_value = None
  3430. if members:
  3431. all_value = members[0]
  3432. for member in members[1:]:
  3433. all_value |= member
  3434. cls.ALL = all_value
  3435. return all_value
  3436. class StrMixin:
  3437. def __str__(self):
  3438. return self._name_.lower()
  3439. class Color(AllMixin, IntFlag):
  3440. RED = auto()
  3441. GREEN = auto()
  3442. BLUE = auto()
  3443. self.assertEqual(Color.RED.value, 1)
  3444. self.assertEqual(Color.GREEN.value, 2)
  3445. self.assertEqual(Color.BLUE.value, 4)
  3446. self.assertEqual(Color.ALL.value, 7)
  3447. self.assertEqual(str(Color.BLUE), '4')
  3448. class Color(AllMixin, StrMixin, IntFlag):
  3449. RED = auto()
  3450. GREEN = auto()
  3451. BLUE = auto()
  3452. __str__ = StrMixin.__str__
  3453. self.assertEqual(Color.RED.value, 1)
  3454. self.assertEqual(Color.GREEN.value, 2)
  3455. self.assertEqual(Color.BLUE.value, 4)
  3456. self.assertEqual(Color.ALL.value, 7)
  3457. self.assertEqual(str(Color.BLUE), 'blue')
  3458. class Color(StrMixin, AllMixin, IntFlag):
  3459. RED = auto()
  3460. GREEN = auto()
  3461. BLUE = auto()
  3462. __str__ = StrMixin.__str__
  3463. self.assertEqual(Color.RED.value, 1)
  3464. self.assertEqual(Color.GREEN.value, 2)
  3465. self.assertEqual(Color.BLUE.value, 4)
  3466. self.assertEqual(Color.ALL.value, 7)
  3467. self.assertEqual(str(Color.BLUE), 'blue')
  3468. @threading_helper.reap_threads
  3469. @threading_helper.requires_working_threading()
  3470. def test_unique_composite(self):
  3471. # override __eq__ to be identity only
  3472. class TestFlag(IntFlag):
  3473. one = auto()
  3474. two = auto()
  3475. three = auto()
  3476. four = auto()
  3477. five = auto()
  3478. six = auto()
  3479. seven = auto()
  3480. eight = auto()
  3481. def __eq__(self, other):
  3482. return self is other
  3483. def __hash__(self):
  3484. return hash(self._value_)
  3485. # have multiple threads competing to complete the composite members
  3486. seen = set()
  3487. failed = False
  3488. def cycle_enum():
  3489. nonlocal failed
  3490. try:
  3491. for i in range(256):
  3492. seen.add(TestFlag(i))
  3493. except Exception:
  3494. failed = True
  3495. threads = [
  3496. threading.Thread(target=cycle_enum)
  3497. for _ in range(8)
  3498. ]
  3499. with threading_helper.start_threads(threads):
  3500. pass
  3501. # check that only 248 members were created
  3502. self.assertFalse(
  3503. failed,
  3504. 'at least one thread failed while creating composite members')
  3505. self.assertEqual(256, len(seen), 'too many composite members created')
  3506. class TestEmptyAndNonLatinStrings(unittest.TestCase):
  3507. def test_empty_string(self):
  3508. with self.assertRaises(ValueError):
  3509. empty_abc = Enum('empty_abc', ('', 'B', 'C'))
  3510. def test_non_latin_character_string(self):
  3511. greek_abc = Enum('greek_abc', ('\u03B1', 'B', 'C'))
  3512. item = getattr(greek_abc, '\u03B1')
  3513. self.assertEqual(item.value, 1)
  3514. def test_non_latin_number_string(self):
  3515. hebrew_123 = Enum('hebrew_123', ('\u05D0', '2', '3'))
  3516. item = getattr(hebrew_123, '\u05D0')
  3517. self.assertEqual(item.value, 1)
  3518. class TestUnique(unittest.TestCase):
  3519. def test_unique_clean(self):
  3520. @unique
  3521. class Clean(Enum):
  3522. one = 1
  3523. two = 'dos'
  3524. tres = 4.0
  3525. #
  3526. @unique
  3527. class Cleaner(IntEnum):
  3528. single = 1
  3529. double = 2
  3530. triple = 3
  3531. def test_unique_dirty(self):
  3532. with self.assertRaisesRegex(ValueError, 'tres.*one'):
  3533. @unique
  3534. class Dirty(Enum):
  3535. one = 1
  3536. two = 'dos'
  3537. tres = 1
  3538. with self.assertRaisesRegex(
  3539. ValueError,
  3540. 'double.*single.*turkey.*triple',
  3541. ):
  3542. @unique
  3543. class Dirtier(IntEnum):
  3544. single = 1
  3545. double = 1
  3546. triple = 3
  3547. turkey = 3
  3548. def test_unique_with_name(self):
  3549. @verify(UNIQUE)
  3550. class Silly(Enum):
  3551. one = 1
  3552. two = 'dos'
  3553. name = 3
  3554. #
  3555. @verify(UNIQUE)
  3556. class Sillier(IntEnum):
  3557. single = 1
  3558. name = 2
  3559. triple = 3
  3560. value = 4
  3561. class TestVerify(unittest.TestCase):
  3562. def test_continuous(self):
  3563. @verify(CONTINUOUS)
  3564. class Auto(Enum):
  3565. FIRST = auto()
  3566. SECOND = auto()
  3567. THIRD = auto()
  3568. FORTH = auto()
  3569. #
  3570. @verify(CONTINUOUS)
  3571. class Manual(Enum):
  3572. FIRST = 3
  3573. SECOND = 4
  3574. THIRD = 5
  3575. FORTH = 6
  3576. #
  3577. with self.assertRaisesRegex(ValueError, 'invalid enum .Missing.: missing values 5, 6, 7, 8, 9, 10, 12'):
  3578. @verify(CONTINUOUS)
  3579. class Missing(Enum):
  3580. FIRST = 3
  3581. SECOND = 4
  3582. THIRD = 11
  3583. FORTH = 13
  3584. #
  3585. with self.assertRaisesRegex(ValueError, 'invalid flag .Incomplete.: missing values 32'):
  3586. @verify(CONTINUOUS)
  3587. class Incomplete(Flag):
  3588. FIRST = 4
  3589. SECOND = 8
  3590. THIRD = 16
  3591. FORTH = 64
  3592. #
  3593. with self.assertRaisesRegex(ValueError, 'invalid flag .StillIncomplete.: missing values 16'):
  3594. @verify(CONTINUOUS)
  3595. class StillIncomplete(Flag):
  3596. FIRST = 4
  3597. SECOND = 8
  3598. THIRD = 11
  3599. FORTH = 32
  3600. def test_composite(self):
  3601. class Bizarre(Flag):
  3602. b = 3
  3603. c = 4
  3604. d = 6
  3605. self.assertEqual(list(Bizarre), [Bizarre.c])
  3606. self.assertEqual(Bizarre.b.value, 3)
  3607. self.assertEqual(Bizarre.c.value, 4)
  3608. self.assertEqual(Bizarre.d.value, 6)
  3609. with self.assertRaisesRegex(
  3610. ValueError,
  3611. "invalid Flag 'Bizarre': aliases b and d are missing combined values of 0x3 .use enum.show_flag_values.value. for details.",
  3612. ):
  3613. @verify(NAMED_FLAGS)
  3614. class Bizarre(Flag):
  3615. b = 3
  3616. c = 4
  3617. d = 6
  3618. #
  3619. self.assertEqual(enum.show_flag_values(3), [1, 2])
  3620. class Bizarre(IntFlag):
  3621. b = 3
  3622. c = 4
  3623. d = 6
  3624. self.assertEqual(list(Bizarre), [Bizarre.c])
  3625. self.assertEqual(Bizarre.b.value, 3)
  3626. self.assertEqual(Bizarre.c.value, 4)
  3627. self.assertEqual(Bizarre.d.value, 6)
  3628. with self.assertRaisesRegex(
  3629. ValueError,
  3630. "invalid Flag 'Bizarre': alias d is missing value 0x2 .use enum.show_flag_values.value. for details.",
  3631. ):
  3632. @verify(NAMED_FLAGS)
  3633. class Bizarre(IntFlag):
  3634. c = 4
  3635. d = 6
  3636. self.assertEqual(enum.show_flag_values(2), [2])
  3637. def test_unique_clean(self):
  3638. @verify(UNIQUE)
  3639. class Clean(Enum):
  3640. one = 1
  3641. two = 'dos'
  3642. tres = 4.0
  3643. #
  3644. @verify(UNIQUE)
  3645. class Cleaner(IntEnum):
  3646. single = 1
  3647. double = 2
  3648. triple = 3
  3649. def test_unique_dirty(self):
  3650. with self.assertRaisesRegex(ValueError, 'tres.*one'):
  3651. @verify(UNIQUE)
  3652. class Dirty(Enum):
  3653. one = 1
  3654. two = 'dos'
  3655. tres = 1
  3656. with self.assertRaisesRegex(
  3657. ValueError,
  3658. 'double.*single.*turkey.*triple',
  3659. ):
  3660. @verify(UNIQUE)
  3661. class Dirtier(IntEnum):
  3662. single = 1
  3663. double = 1
  3664. triple = 3
  3665. turkey = 3
  3666. def test_unique_with_name(self):
  3667. @verify(UNIQUE)
  3668. class Silly(Enum):
  3669. one = 1
  3670. two = 'dos'
  3671. name = 3
  3672. #
  3673. @verify(UNIQUE)
  3674. class Sillier(IntEnum):
  3675. single = 1
  3676. name = 2
  3677. triple = 3
  3678. value = 4
  3679. def test_negative_alias(self):
  3680. @verify(NAMED_FLAGS)
  3681. class Color(Flag):
  3682. RED = 1
  3683. GREEN = 2
  3684. BLUE = 4
  3685. WHITE = -1
  3686. # no error means success
  3687. class TestInternals(unittest.TestCase):
  3688. sunder_names = '_bad_', '_good_', '_what_ho_'
  3689. dunder_names = '__mal__', '__bien__', '__que_que__'
  3690. private_names = '_MyEnum__private', '_MyEnum__still_private'
  3691. private_and_sunder_names = '_MyEnum__private_', '_MyEnum__also_private_'
  3692. random_names = 'okay', '_semi_private', '_weird__', '_MyEnum__'
  3693. def test_sunder(self):
  3694. for name in self.sunder_names + self.private_and_sunder_names:
  3695. self.assertTrue(enum._is_sunder(name), '%r is a not sunder name?' % name)
  3696. for name in self.dunder_names + self.private_names + self.random_names:
  3697. self.assertFalse(enum._is_sunder(name), '%r is a sunder name?' % name)
  3698. def test_dunder(self):
  3699. for name in self.dunder_names:
  3700. self.assertTrue(enum._is_dunder(name), '%r is a not dunder name?' % name)
  3701. for name in self.sunder_names + self.private_names + self.private_and_sunder_names + self.random_names:
  3702. self.assertFalse(enum._is_dunder(name), '%r is a dunder name?' % name)
  3703. def test_is_private(self):
  3704. for name in self.private_names + self.private_and_sunder_names:
  3705. self.assertTrue(enum._is_private('MyEnum', name), '%r is a not private name?')
  3706. for name in self.sunder_names + self.dunder_names + self.random_names:
  3707. self.assertFalse(enum._is_private('MyEnum', name), '%r is a private name?')
  3708. def test_auto_number(self):
  3709. class Color(Enum):
  3710. red = auto()
  3711. blue = auto()
  3712. green = auto()
  3713. self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
  3714. self.assertEqual(Color.red.value, 1)
  3715. self.assertEqual(Color.blue.value, 2)
  3716. self.assertEqual(Color.green.value, 3)
  3717. def test_auto_name(self):
  3718. class Color(Enum):
  3719. def _generate_next_value_(name, start, count, last):
  3720. return name
  3721. red = auto()
  3722. blue = auto()
  3723. green = auto()
  3724. self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
  3725. self.assertEqual(Color.red.value, 'red')
  3726. self.assertEqual(Color.blue.value, 'blue')
  3727. self.assertEqual(Color.green.value, 'green')
  3728. def test_auto_name_inherit(self):
  3729. class AutoNameEnum(Enum):
  3730. def _generate_next_value_(name, start, count, last):
  3731. return name
  3732. class Color(AutoNameEnum):
  3733. red = auto()
  3734. blue = auto()
  3735. green = auto()
  3736. self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
  3737. self.assertEqual(Color.red.value, 'red')
  3738. self.assertEqual(Color.blue.value, 'blue')
  3739. self.assertEqual(Color.green.value, 'green')
  3740. @unittest.skipIf(
  3741. python_version >= (3, 13),
  3742. 'mixed types with auto() no longer supported',
  3743. )
  3744. def test_auto_garbage_ok(self):
  3745. with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
  3746. class Color(Enum):
  3747. red = 'red'
  3748. blue = auto()
  3749. self.assertEqual(Color.blue.value, 1)
  3750. @unittest.skipIf(
  3751. python_version >= (3, 13),
  3752. 'mixed types with auto() no longer supported',
  3753. )
  3754. def test_auto_garbage_corrected_ok(self):
  3755. with self.assertWarnsRegex(DeprecationWarning, 'will require all values to be sortable'):
  3756. class Color(Enum):
  3757. red = 'red'
  3758. blue = 2
  3759. green = auto()
  3760. self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
  3761. self.assertEqual(Color.red.value, 'red')
  3762. self.assertEqual(Color.blue.value, 2)
  3763. self.assertEqual(Color.green.value, 3)
  3764. @unittest.skipIf(
  3765. python_version < (3, 13),
  3766. 'mixed types with auto() will raise in 3.13',
  3767. )
  3768. def test_auto_garbage_fail(self):
  3769. with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
  3770. class Color(Enum):
  3771. red = 'red'
  3772. blue = auto()
  3773. @unittest.skipIf(
  3774. python_version < (3, 13),
  3775. 'mixed types with auto() will raise in 3.13',
  3776. )
  3777. def test_auto_garbage_corrected_fail(self):
  3778. with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'):
  3779. class Color(Enum):
  3780. red = 'red'
  3781. blue = 2
  3782. green = auto()
  3783. def test_auto_order(self):
  3784. with self.assertRaises(TypeError):
  3785. class Color(Enum):
  3786. red = auto()
  3787. green = auto()
  3788. blue = auto()
  3789. def _generate_next_value_(name, start, count, last):
  3790. return name
  3791. def test_auto_order_wierd(self):
  3792. weird_auto = auto()
  3793. weird_auto.value = 'pathological case'
  3794. class Color(Enum):
  3795. red = weird_auto
  3796. def _generate_next_value_(name, start, count, last):
  3797. return name
  3798. blue = auto()
  3799. self.assertEqual(list(Color), [Color.red, Color.blue])
  3800. self.assertEqual(Color.red.value, 'pathological case')
  3801. self.assertEqual(Color.blue.value, 'blue')
  3802. @unittest.skipIf(
  3803. python_version < (3, 13),
  3804. 'auto() will return highest value + 1 in 3.13',
  3805. )
  3806. def test_auto_with_aliases(self):
  3807. class Color(Enum):
  3808. red = auto()
  3809. blue = auto()
  3810. oxford = blue
  3811. crimson = red
  3812. green = auto()
  3813. self.assertIs(Color.crimson, Color.red)
  3814. self.assertIs(Color.oxford, Color.blue)
  3815. self.assertIsNot(Color.green, Color.red)
  3816. self.assertIsNot(Color.green, Color.blue)
  3817. def test_duplicate_auto(self):
  3818. class Dupes(Enum):
  3819. first = primero = auto()
  3820. second = auto()
  3821. third = auto()
  3822. self.assertEqual([Dupes.first, Dupes.second, Dupes.third], list(Dupes))
  3823. def test_multiple_auto_on_line(self):
  3824. class Huh(Enum):
  3825. ONE = auto()
  3826. TWO = auto(), auto()
  3827. THREE = auto(), auto(), auto()
  3828. self.assertEqual(Huh.ONE.value, 1)
  3829. self.assertEqual(Huh.TWO.value, (2, 3))
  3830. self.assertEqual(Huh.THREE.value, (4, 5, 6))
  3831. #
  3832. class Hah(Enum):
  3833. def __new__(cls, value, abbr=None):
  3834. member = object.__new__(cls)
  3835. member._value_ = value
  3836. member.abbr = abbr or value[:3].lower()
  3837. return member
  3838. def _generate_next_value_(name, start, count, last):
  3839. return name
  3840. #
  3841. MONDAY = auto()
  3842. TUESDAY = auto()
  3843. WEDNESDAY = auto(), 'WED'
  3844. THURSDAY = auto(), 'Thu'
  3845. FRIDAY = auto()
  3846. self.assertEqual(Hah.MONDAY.value, 'MONDAY')
  3847. self.assertEqual(Hah.MONDAY.abbr, 'mon')
  3848. self.assertEqual(Hah.TUESDAY.value, 'TUESDAY')
  3849. self.assertEqual(Hah.TUESDAY.abbr, 'tue')
  3850. self.assertEqual(Hah.WEDNESDAY.value, 'WEDNESDAY')
  3851. self.assertEqual(Hah.WEDNESDAY.abbr, 'WED')
  3852. self.assertEqual(Hah.THURSDAY.value, 'THURSDAY')
  3853. self.assertEqual(Hah.THURSDAY.abbr, 'Thu')
  3854. self.assertEqual(Hah.FRIDAY.value, 'FRIDAY')
  3855. self.assertEqual(Hah.FRIDAY.abbr, 'fri')
  3856. #
  3857. class Huh(Enum):
  3858. def _generate_next_value_(name, start, count, last):
  3859. return count+1
  3860. ONE = auto()
  3861. TWO = auto(), auto()
  3862. THREE = auto(), auto(), auto()
  3863. self.assertEqual(Huh.ONE.value, 1)
  3864. self.assertEqual(Huh.TWO.value, (2, 2))
  3865. self.assertEqual(Huh.THREE.value, (3, 3, 3))
  3866. class TestEnumTypeSubclassing(unittest.TestCase):
  3867. pass
  3868. expected_help_output_with_docs = """\
  3869. Help on class Color in module %s:
  3870. class Color(enum.Enum)
  3871. | Color(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
  3872. |\x20\x20
  3873. | Method resolution order:
  3874. | Color
  3875. | enum.Enum
  3876. | builtins.object
  3877. |\x20\x20
  3878. | Data and other attributes defined here:
  3879. |\x20\x20
  3880. | CYAN = <Color.CYAN: 1>
  3881. |\x20\x20
  3882. | MAGENTA = <Color.MAGENTA: 2>
  3883. |\x20\x20
  3884. | YELLOW = <Color.YELLOW: 3>
  3885. |\x20\x20
  3886. | ----------------------------------------------------------------------
  3887. | Data descriptors inherited from enum.Enum:
  3888. |\x20\x20
  3889. | name
  3890. | The name of the Enum member.
  3891. |\x20\x20
  3892. | value
  3893. | The value of the Enum member.
  3894. |\x20\x20
  3895. | ----------------------------------------------------------------------
  3896. | Methods inherited from enum.EnumType:
  3897. |\x20\x20
  3898. | __contains__(member) from enum.EnumType
  3899. | Return True if member is a member of this enum
  3900. | raises TypeError if member is not an enum member
  3901. |\x20\x20\x20\x20\x20\x20
  3902. | note: in 3.12 TypeError will no longer be raised, and True will also be
  3903. | returned if member is the value of a member in this enum
  3904. |\x20\x20
  3905. | __getitem__(name) from enum.EnumType
  3906. | Return the member matching `name`.
  3907. |\x20\x20
  3908. | __iter__() from enum.EnumType
  3909. | Return members in definition order.
  3910. |\x20\x20
  3911. | __len__() from enum.EnumType
  3912. | Return the number of members (no aliases)
  3913. |\x20\x20
  3914. | ----------------------------------------------------------------------
  3915. | Readonly properties inherited from enum.EnumType:
  3916. |\x20\x20
  3917. | __members__
  3918. | Returns a mapping of member name->value.
  3919. |\x20\x20\x20\x20\x20\x20
  3920. | This mapping lists all enum members, including aliases. Note that this
  3921. | is a read-only view of the internal mapping."""
  3922. expected_help_output_without_docs = """\
  3923. Help on class Color in module %s:
  3924. class Color(enum.Enum)
  3925. | Color(value, names=None, *, module=None, qualname=None, type=None, start=1)
  3926. |\x20\x20
  3927. | Method resolution order:
  3928. | Color
  3929. | enum.Enum
  3930. | builtins.object
  3931. |\x20\x20
  3932. | Data and other attributes defined here:
  3933. |\x20\x20
  3934. | YELLOW = <Color.YELLOW: 3>
  3935. |\x20\x20
  3936. | MAGENTA = <Color.MAGENTA: 2>
  3937. |\x20\x20
  3938. | CYAN = <Color.CYAN: 1>
  3939. |\x20\x20
  3940. | ----------------------------------------------------------------------
  3941. | Data descriptors inherited from enum.Enum:
  3942. |\x20\x20
  3943. | name
  3944. |\x20\x20
  3945. | value
  3946. |\x20\x20
  3947. | ----------------------------------------------------------------------
  3948. | Data descriptors inherited from enum.EnumType:
  3949. |\x20\x20
  3950. | __members__"""
  3951. class TestStdLib(unittest.TestCase):
  3952. maxDiff = None
  3953. class Color(Enum):
  3954. CYAN = 1
  3955. MAGENTA = 2
  3956. YELLOW = 3
  3957. def test_pydoc(self):
  3958. # indirectly test __objclass__
  3959. if StrEnum.__doc__ is None:
  3960. expected_text = expected_help_output_without_docs % __name__
  3961. else:
  3962. expected_text = expected_help_output_with_docs % __name__
  3963. output = StringIO()
  3964. helper = pydoc.Helper(output=output)
  3965. helper(self.Color)
  3966. result = output.getvalue().strip()
  3967. self.assertEqual(result, expected_text, result)
  3968. def test_inspect_getmembers(self):
  3969. values = dict((
  3970. ('__class__', EnumType),
  3971. ('__doc__', '...'),
  3972. ('__members__', self.Color.__members__),
  3973. ('__module__', __name__),
  3974. ('YELLOW', self.Color.YELLOW),
  3975. ('MAGENTA', self.Color.MAGENTA),
  3976. ('CYAN', self.Color.CYAN),
  3977. ('name', Enum.__dict__['name']),
  3978. ('value', Enum.__dict__['value']),
  3979. ('__len__', self.Color.__len__),
  3980. ('__contains__', self.Color.__contains__),
  3981. ('__name__', 'Color'),
  3982. ('__getitem__', self.Color.__getitem__),
  3983. ('__qualname__', 'TestStdLib.Color'),
  3984. ('__init_subclass__', getattr(self.Color, '__init_subclass__')),
  3985. ('__iter__', self.Color.__iter__),
  3986. ))
  3987. result = dict(inspect.getmembers(self.Color))
  3988. self.assertEqual(set(values.keys()), set(result.keys()))
  3989. failed = False
  3990. for k in values.keys():
  3991. if k == '__doc__':
  3992. # __doc__ is huge, not comparing
  3993. continue
  3994. if result[k] != values[k]:
  3995. print()
  3996. print('\n%s\n key: %s\n result: %s\nexpected: %s\n%s\n' %
  3997. ('=' * 75, k, result[k], values[k], '=' * 75), sep='')
  3998. failed = True
  3999. if failed:
  4000. self.fail("result does not equal expected, see print above")
  4001. def test_inspect_classify_class_attrs(self):
  4002. # indirectly test __objclass__
  4003. from inspect import Attribute
  4004. values = [
  4005. Attribute(name='__class__', kind='data',
  4006. defining_class=object, object=EnumType),
  4007. Attribute(name='__contains__', kind='method',
  4008. defining_class=EnumType, object=self.Color.__contains__),
  4009. Attribute(name='__doc__', kind='data',
  4010. defining_class=self.Color, object='...'),
  4011. Attribute(name='__getitem__', kind='method',
  4012. defining_class=EnumType, object=self.Color.__getitem__),
  4013. Attribute(name='__iter__', kind='method',
  4014. defining_class=EnumType, object=self.Color.__iter__),
  4015. Attribute(name='__init_subclass__', kind='class method',
  4016. defining_class=object, object=getattr(self.Color, '__init_subclass__')),
  4017. Attribute(name='__len__', kind='method',
  4018. defining_class=EnumType, object=self.Color.__len__),
  4019. Attribute(name='__members__', kind='property',
  4020. defining_class=EnumType, object=EnumType.__members__),
  4021. Attribute(name='__module__', kind='data',
  4022. defining_class=self.Color, object=__name__),
  4023. Attribute(name='__name__', kind='data',
  4024. defining_class=self.Color, object='Color'),
  4025. Attribute(name='__qualname__', kind='data',
  4026. defining_class=self.Color, object='TestStdLib.Color'),
  4027. Attribute(name='YELLOW', kind='data',
  4028. defining_class=self.Color, object=self.Color.YELLOW),
  4029. Attribute(name='MAGENTA', kind='data',
  4030. defining_class=self.Color, object=self.Color.MAGENTA),
  4031. Attribute(name='CYAN', kind='data',
  4032. defining_class=self.Color, object=self.Color.CYAN),
  4033. Attribute(name='name', kind='data',
  4034. defining_class=Enum, object=Enum.__dict__['name']),
  4035. Attribute(name='value', kind='data',
  4036. defining_class=Enum, object=Enum.__dict__['value']),
  4037. ]
  4038. for v in values:
  4039. try:
  4040. v.name
  4041. except AttributeError:
  4042. print(v)
  4043. values.sort(key=lambda item: item.name)
  4044. result = list(inspect.classify_class_attrs(self.Color))
  4045. result.sort(key=lambda item: item.name)
  4046. self.assertEqual(
  4047. len(values), len(result),
  4048. "%s != %s" % ([a.name for a in values], [a.name for a in result])
  4049. )
  4050. failed = False
  4051. for v, r in zip(values, result):
  4052. if r.name in ('__init_subclass__', '__doc__'):
  4053. # not sure how to make the __init_subclass_ Attributes match
  4054. # so as long as there is one, call it good
  4055. # __doc__ is too big to check exactly, so treat the same as __init_subclass__
  4056. for name in ('name','kind','defining_class'):
  4057. if getattr(v, name) != getattr(r, name):
  4058. print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
  4059. failed = True
  4060. elif r != v:
  4061. print('\n%s\n%s\n%s\n%s\n' % ('=' * 75, r, v, '=' * 75), sep='')
  4062. failed = True
  4063. if failed:
  4064. self.fail("result does not equal expected, see print above")
  4065. def test_test_simple_enum(self):
  4066. @_simple_enum(Enum)
  4067. class SimpleColor:
  4068. CYAN = 1
  4069. MAGENTA = 2
  4070. YELLOW = 3
  4071. @bltns.property
  4072. def zeroth(self):
  4073. return 'zeroed %s' % self.name
  4074. class CheckedColor(Enum):
  4075. CYAN = 1
  4076. MAGENTA = 2
  4077. YELLOW = 3
  4078. @bltns.property
  4079. def zeroth(self):
  4080. return 'zeroed %s' % self.name
  4081. self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
  4082. SimpleColor.MAGENTA._value_ = 9
  4083. self.assertRaisesRegex(
  4084. TypeError, "enum mismatch",
  4085. _test_simple_enum, CheckedColor, SimpleColor,
  4086. )
  4087. class CheckedMissing(IntFlag, boundary=KEEP):
  4088. SIXTY_FOUR = 64
  4089. ONE_TWENTY_EIGHT = 128
  4090. TWENTY_FORTY_EIGHT = 2048
  4091. ALL = 2048 + 128 + 64 + 12
  4092. CM = CheckedMissing
  4093. self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
  4094. #
  4095. @_simple_enum(IntFlag, boundary=KEEP)
  4096. class Missing:
  4097. SIXTY_FOUR = 64
  4098. ONE_TWENTY_EIGHT = 128
  4099. TWENTY_FORTY_EIGHT = 2048
  4100. ALL = 2048 + 128 + 64 + 12
  4101. M = Missing
  4102. self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
  4103. #
  4104. _test_simple_enum(CheckedMissing, Missing)
  4105. class MiscTestCase(unittest.TestCase):
  4106. def test__all__(self):
  4107. support.check__all__(self, enum, not_exported={'bin', 'show_flag_values'})
  4108. def test_doc_1(self):
  4109. class Single(Enum):
  4110. ONE = 1
  4111. self.assertEqual(Single.__doc__, None)
  4112. def test_doc_2(self):
  4113. class Double(Enum):
  4114. ONE = 1
  4115. TWO = 2
  4116. self.assertEqual(Double.__doc__, None)
  4117. def test_doc_1(self):
  4118. class Triple(Enum):
  4119. ONE = 1
  4120. TWO = 2
  4121. THREE = 3
  4122. self.assertEqual(Triple.__doc__, None)
  4123. def test_doc_1(self):
  4124. class Quadruple(Enum):
  4125. ONE = 1
  4126. TWO = 2
  4127. THREE = 3
  4128. FOUR = 4
  4129. self.assertEqual(Quadruple.__doc__, None)
  4130. # These are unordered here on purpose to ensure that declaration order
  4131. # makes no difference.
  4132. CONVERT_TEST_NAME_D = 5
  4133. CONVERT_TEST_NAME_C = 5
  4134. CONVERT_TEST_NAME_B = 5
  4135. CONVERT_TEST_NAME_A = 5 # This one should sort first.
  4136. CONVERT_TEST_NAME_E = 5
  4137. CONVERT_TEST_NAME_F = 5
  4138. CONVERT_STRING_TEST_NAME_D = 5
  4139. CONVERT_STRING_TEST_NAME_C = 5
  4140. CONVERT_STRING_TEST_NAME_B = 5
  4141. CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
  4142. CONVERT_STRING_TEST_NAME_E = 5
  4143. CONVERT_STRING_TEST_NAME_F = 5
  4144. # global names for StrEnum._convert_ test
  4145. CONVERT_STR_TEST_2 = 'goodbye'
  4146. CONVERT_STR_TEST_1 = 'hello'
  4147. # We also need values that cannot be compared:
  4148. UNCOMPARABLE_A = 5
  4149. UNCOMPARABLE_C = (9, 1) # naming order is broken on purpose
  4150. UNCOMPARABLE_B = 'value'
  4151. COMPLEX_C = 1j
  4152. COMPLEX_A = 2j
  4153. COMPLEX_B = 3j
  4154. class _ModuleWrapper:
  4155. """We use this class as a namespace for swapping modules."""
  4156. def __init__(self, module):
  4157. self.__dict__.update(module.__dict__)
  4158. class TestConvert(unittest.TestCase):
  4159. def tearDown(self):
  4160. # Reset the module-level test variables to their original integer
  4161. # values, otherwise the already created enum values get converted
  4162. # instead.
  4163. g = globals()
  4164. for suffix in ['A', 'B', 'C', 'D', 'E', 'F']:
  4165. g['CONVERT_TEST_NAME_%s' % suffix] = 5
  4166. g['CONVERT_STRING_TEST_NAME_%s' % suffix] = 5
  4167. for suffix, value in (('A', 5), ('B', (9, 1)), ('C', 'value')):
  4168. g['UNCOMPARABLE_%s' % suffix] = value
  4169. for suffix, value in (('A', 2j), ('B', 3j), ('C', 1j)):
  4170. g['COMPLEX_%s' % suffix] = value
  4171. for suffix, value in (('1', 'hello'), ('2', 'goodbye')):
  4172. g['CONVERT_STR_TEST_%s' % suffix] = value
  4173. def test_convert_value_lookup_priority(self):
  4174. test_type = enum.IntEnum._convert_(
  4175. 'UnittestConvert',
  4176. MODULE,
  4177. filter=lambda x: x.startswith('CONVERT_TEST_'))
  4178. # We don't want the reverse lookup value to vary when there are
  4179. # multiple possible names for a given value. It should always
  4180. # report the first lexigraphical name in that case.
  4181. self.assertEqual(test_type(5).name, 'CONVERT_TEST_NAME_A')
  4182. def test_convert_int(self):
  4183. test_type = enum.IntEnum._convert_(
  4184. 'UnittestConvert',
  4185. MODULE,
  4186. filter=lambda x: x.startswith('CONVERT_TEST_'))
  4187. # Ensure that test_type has all of the desired names and values.
  4188. self.assertEqual(test_type.CONVERT_TEST_NAME_F,
  4189. test_type.CONVERT_TEST_NAME_A)
  4190. self.assertEqual(test_type.CONVERT_TEST_NAME_B, 5)
  4191. self.assertEqual(test_type.CONVERT_TEST_NAME_C, 5)
  4192. self.assertEqual(test_type.CONVERT_TEST_NAME_D, 5)
  4193. self.assertEqual(test_type.CONVERT_TEST_NAME_E, 5)
  4194. # Ensure that test_type only picked up names matching the filter.
  4195. int_dir = dir(int) + [
  4196. 'CONVERT_TEST_NAME_A', 'CONVERT_TEST_NAME_B', 'CONVERT_TEST_NAME_C',
  4197. 'CONVERT_TEST_NAME_D', 'CONVERT_TEST_NAME_E', 'CONVERT_TEST_NAME_F',
  4198. 'CONVERT_TEST_SIGABRT', 'CONVERT_TEST_SIGIOT',
  4199. 'CONVERT_TEST_EIO', 'CONVERT_TEST_EBUS',
  4200. ]
  4201. extra = [name for name in dir(test_type) if name not in enum_dir(test_type)]
  4202. missing = [name for name in enum_dir(test_type) if name not in dir(test_type)]
  4203. self.assertEqual(
  4204. extra + missing,
  4205. [],
  4206. msg='extra names: %r; missing names: %r' % (extra, missing),
  4207. )
  4208. def test_convert_uncomparable(self):
  4209. uncomp = enum.Enum._convert_(
  4210. 'Uncomparable',
  4211. MODULE,
  4212. filter=lambda x: x.startswith('UNCOMPARABLE_'))
  4213. # Should be ordered by `name` only:
  4214. self.assertEqual(
  4215. list(uncomp),
  4216. [uncomp.UNCOMPARABLE_A, uncomp.UNCOMPARABLE_B, uncomp.UNCOMPARABLE_C],
  4217. )
  4218. def test_convert_complex(self):
  4219. uncomp = enum.Enum._convert_(
  4220. 'Uncomparable',
  4221. MODULE,
  4222. filter=lambda x: x.startswith('COMPLEX_'))
  4223. # Should be ordered by `name` only:
  4224. self.assertEqual(
  4225. list(uncomp),
  4226. [uncomp.COMPLEX_A, uncomp.COMPLEX_B, uncomp.COMPLEX_C],
  4227. )
  4228. def test_convert_str(self):
  4229. test_type = enum.StrEnum._convert_(
  4230. 'UnittestConvert',
  4231. MODULE,
  4232. filter=lambda x: x.startswith('CONVERT_STR_'),
  4233. as_global=True)
  4234. # Ensure that test_type has all of the desired names and values.
  4235. self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
  4236. self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
  4237. # Ensure that test_type only picked up names matching the filter.
  4238. str_dir = dir(str) + ['CONVERT_STR_TEST_1', 'CONVERT_STR_TEST_2']
  4239. extra = [name for name in dir(test_type) if name not in enum_dir(test_type)]
  4240. missing = [name for name in enum_dir(test_type) if name not in dir(test_type)]
  4241. self.assertEqual(
  4242. extra + missing,
  4243. [],
  4244. msg='extra names: %r; missing names: %r' % (extra, missing),
  4245. )
  4246. self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % SHORT_MODULE)
  4247. self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
  4248. self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
  4249. def test_convert_raise(self):
  4250. with self.assertRaises(AttributeError):
  4251. enum.IntEnum._convert(
  4252. 'UnittestConvert',
  4253. MODULE,
  4254. filter=lambda x: x.startswith('CONVERT_TEST_'))
  4255. def test_convert_repr_and_str(self):
  4256. test_type = enum.IntEnum._convert_(
  4257. 'UnittestConvert',
  4258. MODULE,
  4259. filter=lambda x: x.startswith('CONVERT_STRING_TEST_'),
  4260. as_global=True)
  4261. self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % SHORT_MODULE)
  4262. self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), '5')
  4263. self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
  4264. # helpers
  4265. def enum_dir(cls):
  4266. interesting = set([
  4267. '__class__', '__contains__', '__doc__', '__getitem__',
  4268. '__iter__', '__len__', '__members__', '__module__',
  4269. '__name__', '__qualname__',
  4270. ]
  4271. + cls._member_names_
  4272. )
  4273. if cls._new_member_ is not object.__new__:
  4274. interesting.add('__new__')
  4275. if cls.__init_subclass__ is not object.__init_subclass__:
  4276. interesting.add('__init_subclass__')
  4277. if cls._member_type_ is object:
  4278. return sorted(interesting)
  4279. else:
  4280. # return whatever mixed-in data type has
  4281. return sorted(set(dir(cls._member_type_)) | interesting)
  4282. def member_dir(member):
  4283. if member.__class__._member_type_ is object:
  4284. allowed = set(['__class__', '__doc__', '__eq__', '__hash__', '__module__', 'name', 'value'])
  4285. else:
  4286. allowed = set(dir(member))
  4287. for cls in member.__class__.mro():
  4288. for name, obj in cls.__dict__.items():
  4289. if name[0] == '_':
  4290. continue
  4291. if isinstance(obj, enum.property):
  4292. if obj.fget is not None or name not in member._member_map_:
  4293. allowed.add(name)
  4294. else:
  4295. allowed.discard(name)
  4296. else:
  4297. allowed.add(name)
  4298. return sorted(allowed)
  4299. missing = object()
  4300. if __name__ == '__main__':
  4301. unittest.main()