needed to make reftracking test mode work functools wrapsfunc def wrapperargs kwargs ctx contextvars context return ctx runfunc args kwargs return wrapper class contexttestunittest testcase def testcontextvarnew1self with self assertraisesregextypeerror takes exactly 1 contextvars contextvar with self assertraisesregextypeerror must be a str contextvars contextvar1 c contextvars contextvar aaa self assertequalc name aaa with self assertraisesattributeerror c name bbb self assertnotequalhashc hash aaa isolatedcontext def testcontextvarrepr1self c contextvars contextvar a self assertin a reprc c contextvars contextvar a default123 self assertin 123 reprc lst c contextvars contextvar a defaultlst lst appendc self assertin reprc self assertin reprlst t c set1 self assertinreprc reprt self assertnotin used reprt c resett self assertin used reprt def testcontextsubclassing1self with self assertraisesregextypeerror not an acceptable base type class mycontextvarcontextvars contextvar potentially we might want contextvars to be subclassable pass with self assertraisesregextypeerror not an acceptable base type class mycontextcontextvars context pass with self assertraisesregextypeerror not an acceptable base type class mytokencontextvars token pass def testcontextnew1self with self assertraisesregextypeerror any arguments contextvars context1 with self assertraisesregextypeerror any arguments contextvars context1 a1 with self assertraisesregextypeerror any arguments contextvars contexta1 contextvars context def testcontexttyperrors1self ctx contextvars context with self assertraisesregextypeerror contextvar key was expected ctx1 with self assertraisesregextypeerror contextvar key was expected 1 in ctx with self assertraisesregextypeerror contextvar key was expected ctx get1 def testcontextgetcontext1self ctx contextvars copycontext self assertisinstancectx contextvars context def testcontextrun1self ctx contextvars context with self assertraisesregextypeerror missing 1 required ctx run def testcontextrun2self ctx contextvars context def funcargs kwargs kwargs spam foo args bar return args kwargs for f in func functools partialfunc partial doesn t support fastcall self assertequalctx runf bar spam foo self assertequalctx runf 1 1 bar spam foo self assertequal ctx runf a2 bar a 2 spam foo self assertequal ctx runf 11 a2 11 bar a 2 spam foo a self assertequal ctx runf 11 a 11 bar spam foo self assertequala def testcontextrun3self ctx contextvars context def funcargs kwargs 1 0 with self assertraiseszerodivisionerror ctx runfunc with self assertraiseszerodivisionerror ctx runfunc 1 2 with self assertraiseszerodivisionerror ctx runfunc 1 2 a123 isolatedcontext def testcontextrun4self ctx1 contextvars context ctx2 contextvars context var contextvars contextvar var def func2 self assertisnonevar getnone def func1 self assertisnonevar getnone var set spam ctx2 runfunc2 self assertequalvar getnone spam cur contextvars copycontext self assertequallencur 1 self assertequalcurvar spam return cur returnedctx ctx1 runfunc1 self assertequalctx1 returnedctx self assertequalreturnedctxvar spam self assertinvar returnedctx def testcontextrun5self ctx contextvars context var contextvars contextvar var def func self assertisnonevar getnone var set spam 1 0 with self assertraiseszerodivisionerror ctx runfunc self assertisnonevar getnone def testcontextrun6self ctx contextvars context c contextvars contextvar a default0 def fun self assertequalc get 0 self assertisnonectx getc c set42 self assertequalc get 42 self assertequalctx getc 42 ctx runfun def testcontextrun7self ctx contextvars context def fun with self assertraisesregexruntimeerror is already entered ctx runfun ctx runfun isolatedcontext def testcontextgetset1self c contextvars contextvar c with self assertraiseslookuperror c get self assertisnonec getnone t0 c set42 self assertequalc get 42 self assertequalc getnone 42 self assertist0 oldvalue t0 missing self assertist0 oldvalue contextvars token missing self assertist0 var c t c set spam self assertequalc get spam self assertequalc getnone spam self assertequalt oldvalue 42 c resett self assertequalc get 42 self assertequalc getnone 42 c set spam2 with self assertraisesregexruntimeerror has already been used c resett self assertequalc get spam2 ctx1 contextvars copycontext self assertinc ctx1 c resett0 with self assertraisesregexruntimeerror has already been used c resett0 self assertisnonec getnone self assertinc ctx1 self assertequalctx1c spam2 self assertequalctx1 getc aa spam2 self assertequallenctx1 1 self assertequallistctx1 items c spam2 self assertequallistctx1 values spam2 self assertequallistctx1 keys c self assertequallistctx1 c ctx2 contextvars copycontext self assertnotinc ctx2 with self assertraiseskeyerror ctx2c self assertequalctx2 getc aa aa self assertequallenctx2 0 self assertequallistctx2 isolatedcontext def testcontextgetset2self v1 contextvars contextvar v1 v2 contextvars contextvar v2 t1 v1 set42 with self assertraisesregexvalueerror by a different v2 resett1 isolatedcontext def testcontextgetset3self c contextvars contextvar c default42 ctx contextvars context def fun self assertequalc get 42 with self assertraiseskeyerror ctxc self assertisnonectx getc self assertequalctx getc spam spam self assertnotinc ctx self assertequallistctx keys t c set1 self assertequallistctx keys c self assertequalctxc 1 c resett self assertequallistctx keys with self assertraiseskeyerror ctxc ctx runfun isolatedcontext def testcontextgetset4self c contextvars contextvar c default42 ctx contextvars context tok ctx runc set 1 with self assertraisesregexvalueerror different context c resettok isolatedcontext def testcontextgetset5self c contextvars contextvar c default42 c set def fun c set c get append42 self assertequalc get 42 contextvars copycontext runfun self assertequalc get def testcontextcopy1self ctx1 contextvars context c contextvars contextvar c default42 def ctx1fun c set10 ctx2 ctx1 copy self assertequalctx2c 10 c set20 self assertequalctx1c 20 self assertequalctx2c 10 ctx2 runctx2fun self assertequalctx1c 20 self assertequalctx2c 30 def ctx2fun self assertequalc get 10 c set30 self assertequalc get 30 ctx1 runctx1fun isolatedcontext threadinghelper requiresworkingthreading def testcontextthreads1self cvar contextvars contextvar cvar def subnum for i in range10 cvar setnum i time sleeprandom uniform0 001 0 05 self assertequalcvar get num i return num tp concurrent futures threadpoolexecutormaxworkers10 try results listtp mapsub range10 finally tp shutdown self assertequalresults listrange10 hamt tests class hashkey crasher none def initself hash name erroroneqtonone assert hash 1 self name name self hash hash self erroroneqto erroroneqto def reprself return f key name self name hash self hash def hashself if self crasher is not none and self crasher erroronhash raise hashingerror return self hash def eqself other if not isinstanceother hashkey return notimplemented if self crasher is not none and self crasher erroroneq raise eqerror if self erroroneqto is not none and self erroroneqto is other raise valueerrorf cannot compare self r to other r if other erroroneqto is not none and other erroroneqto is self raise valueerrorf cannot compare other r to self r return self name self hash other name other hash class keystrstr def hashself if hashkey crasher is not none and hashkey crasher erroronhash raise hashingerror return super hash def eqself other if hashkey crasher is not none and hashkey crasher erroroneq raise eqerror return super eqother class haskkeycrasher def initself erroronhashfalse erroroneqfalse self erroronhash erroronhash self erroroneq erroroneq def enterself if hashkey crasher is not none raise runtimeerror cannot nest crashers hashkey crasher self def exitself exc hashkey crasher none class hashingerrorexception pass class eqerrorexception pass unittest skipifhamt is none testinternalcapi hamt not available class hamttestunittest testcase def testhashkeyhelper1self k1 hashkey10 aaa k2 hashkey10 bbb self assertnotequalk1 k2 self assertequalhashk1 hashk2 d dict dk1 a dk2 b self assertequaldk1 a self assertequaldk2 b def testhamtbasics1self h hamt h none noqa def testhamtbasics2self h hamt self assertequallenh 0 h2 h set a b self assertisnoth h2 self assertequallenh 0 self assertequallenh2 1 self assertisnoneh get a self assertequalh get a 42 42 self assertequalh2 get a b h3 h2 set b 10 self assertisnoth2 h3 self assertequallenh 0 self assertequallenh2 1 self assertequallenh3 2 self assertequalh3 get a b self assertequalh3 get b 10 self assertisnoneh get b self assertisnoneh2 get b self assertisnoneh get a self assertequalh2 get a b h h2 h3 none def testhamtbasics3self h hamt o object h1 h set 1 o h2 h1 set 1 o self assertish1 h2 def testhamtbasics4self h hamt h1 h set key h2 h1 set key self assertisnoth1 h2 self assertequallenh1 1 self assertequallenh2 1 self assertisnoth1 get key h2 get key def testhamtcollision1self k1 hashkey10 aaa k2 hashkey10 bbb k3 hashkey10 ccc h hamt h2 h setk1 a h3 h2 setk2 b self assertequalh getk1 none self assertequalh getk2 none self assertequalh2 getk1 a self assertequalh2 getk2 none self assertequalh3 getk1 a self assertequalh3 getk2 b h4 h3 setk2 cc h5 h4 setk3 aa self assertequalh3 getk1 a self assertequalh3 getk2 b self assertequalh4 getk1 a self assertequalh4 getk2 cc self assertequalh4 getk3 none self assertequalh5 getk1 a self assertequalh5 getk2 cc self assertequalh5 getk2 cc self assertequalh5 getk3 aa self assertequallenh 0 self assertequallenh2 1 self assertequallenh3 2 self assertequallenh4 2 self assertequallenh5 3 def testhamtcollision3self test that iteration works with the deepest tree possible https github compythoncpythonissues93065 c hashkey0b10000000000000000000000000000000 c d hashkey0b10000000000000000000000000000000 d e hashkey0b00000000000000000000000000000000 e h hamt h h setc c h h setd d h h sete e bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize2 count1 bitmap0b1 null bitmapnodesize4 count2 bitmap0b101 key name e hash 0 e null collisionnodesize4 id0x107a24520 key name c hash 2147483648 c key name d hash 2147483648 d self assertequalk name for k in h keys c d e support requiresresource cpu def testhamtstressself collectionsize 7000 testitersevery 647 crashhashevery 97 crasheqevery 11 runxtimes 3 for in rangerunxtimes h hamt d dict for i in rangecollectionsize key keystri if not i crashhashevery with haskkeycrashererroronhashtrue with self assertraiseshashingerror h setkey i h h setkey i if not i crasheqevery with haskkeycrashererroroneqtrue with self assertraiseseqerror h getkeystri really trigger eq dkey i self assertequallend lenh if not i testitersevery self assertequalseth items setd items self assertequallenh items lend items self assertequallenh collectionsize for key in rangecollectionsize self assertequalh getkeystrkey not found key keystodelete listrangecollectionsize random shufflekeystodelete for iteri i in enumeratekeystodelete key keystri if not iteri crashhashevery with haskkeycrashererroronhashtrue with self assertraiseshashingerror h deletekey if not iteri crasheqevery with haskkeycrashererroroneqtrue with self assertraiseseqerror h deletekeystri h h deletekey self assertequalh getkey not found not found del dkey self assertequallend lenh if iteri collectionsize 2 hm h dm d copy if not iteri testitersevery self assertequalseth keys setd keys self assertequallenh keys lend keys self assertequallend 0 self assertequallenh 0 for key in dm self assertequalhm getstrkey dmkey self assertequallendm lenhm for i key in enumeratekeystodelete hm hm deletestrkey self assertequalhm getstrkey not found not found dm popstrkey none self assertequallend lenh if not i testitersevery self assertequalseth values setd values self assertequallenh values lend values self assertequallend 0 self assertequallenh 0 self assertequallisth items def testhamtdelete1self a hashkey100 a b hashkey101 b c hashkey102 c d hashkey103 d e hashkey104 e z hashkey100 z er hashkey103 er erroroneqtod h hamt h h seta a h h setb b h h setc c h h setd d h h sete e origlen lenh bitmapnodesize10 bitmap0b111110000 id0x10eadc618 key name a hash 100 a key name b hash 101 b key name c hash 102 c key name d hash 103 d key name e hash 104 e h h deletec self assertequallenh origlen 1 with self assertraisesregexvalueerror cannot compare h deleteer h h deleted self assertequallenh origlen 2 h2 h deletez self assertish2 h h h deletea self assertequallenh origlen 3 self assertequalh geta 42 42 self assertequalh getb b self assertequalh gete e def testhamtdelete2self a hashkey100 a b hashkey201001 b c hashkey101001 c d hashkey103 d e hashkey104 e z hashkey100 z er hashkey201001 er erroroneqtob h hamt h h seta a h h setb b h h setc c h h setd d h h sete e origlen lenh bitmapnodesize8 bitmap0b1110010000 key name a hash 100 a key name d hash 103 d key name e hash 104 e null bitmapnodesize4 bitmap0b100000000001000000000 key name b hash 201001 b key name c hash 101001 c with self assertraisesregexvalueerror cannot compare h deleteer h h deletez self assertequallenh origlen h h deletec self assertequallenh origlen 1 h h deleteb self assertequallenh origlen 2 h h deletea self assertequallenh origlen 3 self assertequalh getd d self assertequalh gete e h h deletea h h deleteb h h deleted h h deletee self assertequallenh 0 def testhamtdelete3self a hashkey100 a b hashkey101 b c hashkey100100 c d hashkey100100 d e hashkey104 e h hamt h h seta a h h setb b h h setc c h h setd d h h sete e origlen lenh bitmapnodesize6 bitmap0b100110000 null bitmapnodesize4 bitmap0b1000000000000000000001000 key name a hash 100 a null collisionnodesize4 id0x108572410 key name c hash 100100 c key name d hash 100100 d key name b hash 101 b key name e hash 104 e h h deletea self assertequallenh origlen 1 h h deletee self assertequallenh origlen 2 self assertequalh getc c self assertequalh getb b def testhamtdelete4self a hashkey100 a b hashkey101 b c hashkey100100 c d hashkey100100 d e hashkey100100 e h hamt h h seta a h h setb b h h setc c h h setd d h h sete e origlen lenh bitmapnodesize4 bitmap0b110000 null bitmapnodesize4 bitmap0b1000000000000000000001000 key name a hash 100 a null collisionnodesize6 id0x10515ef30 key name c hash 100100 c key name d hash 100100 d key name e hash 100100 e key name b hash 101 b h h deleted self assertequallenh origlen 1 h h deletee self assertequallenh origlen 2 h h deletec self assertequallenh origlen 3 h h deletea self assertequallenh origlen 4 h h deleteb self assertequallenh 0 def testhamtdelete5self h hamt keys for i in range17 key hashkeyi stri keys appendkey h h setkey f vali collisionkey16 hashkey16 18 h h setcollisionkey16 collision arraynodeid0x10f8b9318 0 bitmapnodesize2 count1 bitmap0b1 key name 0 hash 0 val0 14 more bitmapnodes 15 bitmapnodesize2 count1 bitmap0b1 key name 15 hash 15 val15 16 bitmapnodesize2 count1 bitmap0b1 null collisionnodesize4 id0x10f2f5af8 key name 16 hash 16 val16 key name 18 hash 16 collision self assertequallenh 18 h h deletekeys2 self assertequallenh 17 h h deletecollisionkey16 self assertequallenh 16 h h deletekeys16 self assertequallenh 15 h h deletekeys1 self assertequallenh 14 h h deletekeys1 self assertequallenh 14 for key in keys h h deletekey self assertequallenh 0 def testhamtitems1self a hashkey100 a b hashkey201001 b c hashkey101001 c d hashkey103 d e hashkey104 e f hashkey110 f h hamt h h seta a h h setb b h h setc c h h setd d h h sete e h h setf f it h items self assertequal setlistit a a b b c c d d e e f f def testhamtitems2self a hashkey100 a b hashkey101 b c hashkey100100 c d hashkey100100 d e hashkey100100 e f hashkey110 f h hamt h h seta a h h setb b h h setc c h h setd d h h sete e h h setf f it h items self assertequal setlistit a a b b c c d d e e f f def testhamtkeys1self a hashkey100 a b hashkey101 b c hashkey100100 c d hashkey100100 d e hashkey100100 e f hashkey110 f h hamt h h seta a h h setb b h h setc c h h setd d h h sete e h h setf f self assertequalsetlisth keys a b c d e f self assertequalsetlisth a b c d e f def testhamtitems3self h hamt self assertequallenh items 0 self assertequallisth items def testhamteq1self a hashkey100 a b hashkey101 b c hashkey100100 c d hashkey100100 d e hashkey120 e h1 hamt h1 h1 seta a h1 h1 setb b h1 h1 setc c h1 h1 setd d h2 hamt h2 h2 seta a self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 setb b self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 setc c self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 setd d2 self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 setd d self asserttrueh1 h2 self assertfalseh1 h2 h2 h2 sete e self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 deleted self assertfalseh1 h2 self asserttrueh1 h2 h2 h2 sete d self assertfalseh1 h2 self asserttrueh1 h2 def testhamteq2self a hashkey100 a er hashkey100 er erroroneqtoa h1 hamt h1 h1 seta a h2 hamt h2 h2 seter a with self assertraisesregexvalueerror cannot compare h1 h2 with self assertraisesregexvalueerror cannot compare h1 h2 def testhamtgc1self a hashkey100 a h hamt h h set0 0 empty hamt node is memoized in hamt c ref weakref refh a a appenda a appendh b a appendb b appenda h h seta b del h a b gc collect gc collect gc collect self assertisnoneref def testhamtgc2self a hashkey100 a b hashkey101 b h hamt h h seta a h h seta h ref weakref refh hi h items nexthi del h hi gc collect gc collect gc collect self assertisnoneref def testhamtin1self a hashkey100 a aa hashkey100 a b hashkey101 b h hamt h h seta 1 self asserttruea in h self assertfalseb in h with self assertraiseseqerror with haskkeycrashererroroneqtrue aa in h with self assertraiseshashingerror with haskkeycrashererroronhashtrue aa in h def testhamtgetitem1self a hashkey100 a aa hashkey100 a b hashkey101 b h hamt h h seta 1 self assertequalha 1 self assertequalhaa 1 with self assertraiseskeyerror hb with self assertraiseseqerror with haskkeycrashererroroneqtrue haa with self assertraiseshashingerror with haskkeycrashererroronhashtrue haa if name main unittest main needed to make reftracking test mode work potentially we might want contextvars to be subclassable partial doesn t support fastcall hamt tests noqa test that iteration works with the deepest tree possible https github com python cpython issues 93065 bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 2 count 1 bitmap 0b1 null bitmapnode size 4 count 2 bitmap 0b101 key name e hash 0 e null collisionnode size 4 id 0x107a24520 key name c hash 2147483648 c key name d hash 2147483648 d really trigger __eq__ bitmapnode size 10 bitmap 0b111110000 id 0x10eadc618 key name a hash 100 a key name b hash 101 b key name c hash 102 c key name d hash 103 d key name e hash 104 e bitmapnode size 8 bitmap 0b1110010000 key name a hash 100 a key name d hash 103 d key name e hash 104 e null bitmapnode size 4 bitmap 0b100000000001000000000 key name b hash 201001 b key name c hash 101001 c bitmapnode size 6 bitmap 0b100110000 null bitmapnode size 4 bitmap 0b1000000000000000000001000 key name a hash 100 a null collisionnode size 4 id 0x108572410 key name c hash 100100 c key name d hash 100100 d key name b hash 101 b key name e hash 104 e bitmapnode size 4 bitmap 0b110000 null bitmapnode size 4 bitmap 0b1000000000000000000001000 key name a hash 100 a null collisionnode size 6 id 0x10515ef30 key name c hash 100100 c key name d hash 100100 d key name e hash 100100 e key name b hash 101 b arraynode id 0x10f8b9318 0 bitmapnode size 2 count 1 bitmap 0b1 key name 0 hash 0 val 0 14 more bitmapnodes 15 bitmapnode size 2 count 1 bitmap 0b1 key name 15 hash 15 val 15 16 bitmapnode size 2 count 1 bitmap 0b1 null collisionnode size 4 id 0x10f2f5af8 key name 16 hash 16 val 16 key name 18 hash 16 collision empty hamt node is memoized in hamt c
import concurrent.futures
import contextvars
import functools
import gc
import random
import time
import unittest
import weakref
from test import support
from test.support import threading_helper

try:
    from _testinternalcapi import hamt
except ImportError:
    hamt = None


def isolated_context(func):
    
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        ctx = contextvars.Context()
        return ctx.run(func, *args, **kwargs)
    return wrapper


class ContextTest(unittest.TestCase):
    def test_context_var_new_1(self):
        with self.assertRaisesRegex(TypeError, 'takes exactly 1'):
            contextvars.ContextVar()

        with self.assertRaisesRegex(TypeError, 'must be a str'):
            contextvars.ContextVar(1)

        c = contextvars.ContextVar('aaa')
        self.assertEqual(c.name, 'aaa')

        with self.assertRaises(AttributeError):
            c.name = 'bbb'

        self.assertNotEqual(hash(c), hash('aaa'))

    @isolated_context
    def test_context_var_repr_1(self):
        c = contextvars.ContextVar('a')
        self.assertIn('a', repr(c))

        c = contextvars.ContextVar('a', default=123)
        self.assertIn('123', repr(c))

        lst = []
        c = contextvars.ContextVar('a', default=lst)
        lst.append(c)
        self.assertIn('...', repr(c))
        self.assertIn('...', repr(lst))

        t = c.set(1)
        self.assertIn(repr(c), repr(t))
        self.assertNotIn(' used ', repr(t))
        c.reset(t)
        self.assertIn(' used ', repr(t))

    def test_context_subclassing_1(self):
        with self.assertRaisesRegex(TypeError, 'not an acceptable base type'):
            class MyContextVar(contextvars.ContextVar):
                
                pass

        with self.assertRaisesRegex(TypeError, 'not an acceptable base type'):
            class MyContext(contextvars.Context):
                pass

        with self.assertRaisesRegex(TypeError, 'not an acceptable base type'):
            class MyToken(contextvars.Token):
                pass

    def test_context_new_1(self):
        with self.assertRaisesRegex(TypeError, 'any arguments'):
            contextvars.Context(1)
        with self.assertRaisesRegex(TypeError, 'any arguments'):
            contextvars.Context(1, a=1)
        with self.assertRaisesRegex(TypeError, 'any arguments'):
            contextvars.Context(a=1)
        contextvars.Context(**{})

    def test_context_typerrors_1(self):
        ctx = contextvars.Context()

        with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'):
            ctx[1]
        with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'):
            1 in ctx
        with self.assertRaisesRegex(TypeError, 'ContextVar key was expected'):
            ctx.get(1)

    def test_context_get_context_1(self):
        ctx = contextvars.copy_context()
        self.assertIsInstance(ctx, contextvars.Context)

    def test_context_run_1(self):
        ctx = contextvars.Context()

        with self.assertRaisesRegex(TypeError, 'missing 1 required'):
            ctx.run()

    def test_context_run_2(self):
        ctx = contextvars.Context()

        def func(*args, **kwargs):
            kwargs['spam'] = 'foo'
            args += ('bar',)
            return args, kwargs

        for f in (func, functools.partial(func)):
            

            self.assertEqual(ctx.run(f), (('bar',), {'spam': 'foo'}))
            self.assertEqual(ctx.run(f, 1), ((1, 'bar'), {'spam': 'foo'}))

            self.assertEqual(
                ctx.run(f, a=2),
                (('bar',), {'a': 2, 'spam': 'foo'}))

            self.assertEqual(
                ctx.run(f, 11, a=2),
                ((11, 'bar'), {'a': 2, 'spam': 'foo'}))

            a = {}
            self.assertEqual(
                ctx.run(f, 11, **a),
                ((11, 'bar'), {'spam': 'foo'}))
            self.assertEqual(a, {})

    def test_context_run_3(self):
        ctx = contextvars.Context()

        def func(*args, **kwargs):
            1 / 0

        with self.assertRaises(ZeroDivisionError):
            ctx.run(func)
        with self.assertRaises(ZeroDivisionError):
            ctx.run(func, 1, 2)
        with self.assertRaises(ZeroDivisionError):
            ctx.run(func, 1, 2, a=123)

    @isolated_context
    def test_context_run_4(self):
        ctx1 = contextvars.Context()
        ctx2 = contextvars.Context()
        var = contextvars.ContextVar('var')

        def func2():
            self.assertIsNone(var.get(None))

        def func1():
            self.assertIsNone(var.get(None))
            var.set('spam')
            ctx2.run(func2)
            self.assertEqual(var.get(None), 'spam')

            cur = contextvars.copy_context()
            self.assertEqual(len(cur), 1)
            self.assertEqual(cur[var], 'spam')
            return cur

        returned_ctx = ctx1.run(func1)
        self.assertEqual(ctx1, returned_ctx)
        self.assertEqual(returned_ctx[var], 'spam')
        self.assertIn(var, returned_ctx)

    def test_context_run_5(self):
        ctx = contextvars.Context()
        var = contextvars.ContextVar('var')

        def func():
            self.assertIsNone(var.get(None))
            var.set('spam')
            1 / 0

        with self.assertRaises(ZeroDivisionError):
            ctx.run(func)

        self.assertIsNone(var.get(None))

    def test_context_run_6(self):
        ctx = contextvars.Context()
        c = contextvars.ContextVar('a', default=0)

        def fun():
            self.assertEqual(c.get(), 0)
            self.assertIsNone(ctx.get(c))

            c.set(42)
            self.assertEqual(c.get(), 42)
            self.assertEqual(ctx.get(c), 42)

        ctx.run(fun)

    def test_context_run_7(self):
        ctx = contextvars.Context()

        def fun():
            with self.assertRaisesRegex(RuntimeError, 'is already entered'):
                ctx.run(fun)

        ctx.run(fun)

    @isolated_context
    def test_context_getset_1(self):
        c = contextvars.ContextVar('c')
        with self.assertRaises(LookupError):
            c.get()

        self.assertIsNone(c.get(None))

        t0 = c.set(42)
        self.assertEqual(c.get(), 42)
        self.assertEqual(c.get(None), 42)
        self.assertIs(t0.old_value, t0.MISSING)
        self.assertIs(t0.old_value, contextvars.Token.MISSING)
        self.assertIs(t0.var, c)

        t = c.set('spam')
        self.assertEqual(c.get(), 'spam')
        self.assertEqual(c.get(None), 'spam')
        self.assertEqual(t.old_value, 42)
        c.reset(t)

        self.assertEqual(c.get(), 42)
        self.assertEqual(c.get(None), 42)

        c.set('spam2')
        with self.assertRaisesRegex(RuntimeError, 'has already been used'):
            c.reset(t)
        self.assertEqual(c.get(), 'spam2')

        ctx1 = contextvars.copy_context()
        self.assertIn(c, ctx1)

        c.reset(t0)
        with self.assertRaisesRegex(RuntimeError, 'has already been used'):
            c.reset(t0)
        self.assertIsNone(c.get(None))

        self.assertIn(c, ctx1)
        self.assertEqual(ctx1[c], 'spam2')
        self.assertEqual(ctx1.get(c, 'aa'), 'spam2')
        self.assertEqual(len(ctx1), 1)
        self.assertEqual(list(ctx1.items()), [(c, 'spam2')])
        self.assertEqual(list(ctx1.values()), ['spam2'])
        self.assertEqual(list(ctx1.keys()), [c])
        self.assertEqual(list(ctx1), [c])

        ctx2 = contextvars.copy_context()
        self.assertNotIn(c, ctx2)
        with self.assertRaises(KeyError):
            ctx2[c]
        self.assertEqual(ctx2.get(c, 'aa'), 'aa')
        self.assertEqual(len(ctx2), 0)
        self.assertEqual(list(ctx2), [])

    @isolated_context
    def test_context_getset_2(self):
        v1 = contextvars.ContextVar('v1')
        v2 = contextvars.ContextVar('v2')

        t1 = v1.set(42)
        with self.assertRaisesRegex(ValueError, 'by a different'):
            v2.reset(t1)

    @isolated_context
    def test_context_getset_3(self):
        c = contextvars.ContextVar('c', default=42)
        ctx = contextvars.Context()

        def fun():
            self.assertEqual(c.get(), 42)
            with self.assertRaises(KeyError):
                ctx[c]
            self.assertIsNone(ctx.get(c))
            self.assertEqual(ctx.get(c, 'spam'), 'spam')
            self.assertNotIn(c, ctx)
            self.assertEqual(list(ctx.keys()), [])

            t = c.set(1)
            self.assertEqual(list(ctx.keys()), [c])
            self.assertEqual(ctx[c], 1)

            c.reset(t)
            self.assertEqual(list(ctx.keys()), [])
            with self.assertRaises(KeyError):
                ctx[c]

        ctx.run(fun)

    @isolated_context
    def test_context_getset_4(self):
        c = contextvars.ContextVar('c', default=42)
        ctx = contextvars.Context()

        tok = ctx.run(c.set, 1)

        with self.assertRaisesRegex(ValueError, 'different Context'):
            c.reset(tok)

    @isolated_context
    def test_context_getset_5(self):
        c = contextvars.ContextVar('c', default=42)
        c.set([])

        def fun():
            c.set([])
            c.get().append(42)
            self.assertEqual(c.get(), [42])

        contextvars.copy_context().run(fun)
        self.assertEqual(c.get(), [])

    def test_context_copy_1(self):
        ctx1 = contextvars.Context()
        c = contextvars.ContextVar('c', default=42)

        def ctx1_fun():
            c.set(10)

            ctx2 = ctx1.copy()
            self.assertEqual(ctx2[c], 10)

            c.set(20)
            self.assertEqual(ctx1[c], 20)
            self.assertEqual(ctx2[c], 10)

            ctx2.run(ctx2_fun)
            self.assertEqual(ctx1[c], 20)
            self.assertEqual(ctx2[c], 30)

        def ctx2_fun():
            self.assertEqual(c.get(), 10)
            c.set(30)
            self.assertEqual(c.get(), 30)

        ctx1.run(ctx1_fun)

    @isolated_context
    @threading_helper.requires_working_threading()
    def test_context_threads_1(self):
        cvar = contextvars.ContextVar('cvar')

        def sub(num):
            for i in range(10):
                cvar.set(num + i)
                time.sleep(random.uniform(0.001, 0.05))
                self.assertEqual(cvar.get(), num + i)
            return num

        tp = concurrent.futures.ThreadPoolExecutor(max_workers=10)
        try:
            results = list(tp.map(sub, range(10)))
        finally:
            tp.shutdown()
        self.assertEqual(results, list(range(10)))





class HashKey:
    _crasher = None

    def __init__(self, hash, name, *, error_on_eq_to=None):
        assert hash != -1
        self.name = name
        self.hash = hash
        self.error_on_eq_to = error_on_eq_to

    def __repr__(self):
        return f'<Key name:{self.name} hash:{self.hash}>'

    def __hash__(self):
        if self._crasher is not None and self._crasher.error_on_hash:
            raise HashingError

        return self.hash

    def __eq__(self, other):
        if not isinstance(other, HashKey):
            return NotImplemented

        if self._crasher is not None and self._crasher.error_on_eq:
            raise EqError

        if self.error_on_eq_to is not None and self.error_on_eq_to is other:
            raise ValueError(f'cannot compare {self!r} to {other!r}')
        if other.error_on_eq_to is not None and other.error_on_eq_to is self:
            raise ValueError(f'cannot compare {other!r} to {self!r}')

        return (self.name, self.hash) == (other.name, other.hash)


class KeyStr(str):
    def __hash__(self):
        if HashKey._crasher is not None and HashKey._crasher.error_on_hash:
            raise HashingError
        return super().__hash__()

    def __eq__(self, other):
        if HashKey._crasher is not None and HashKey._crasher.error_on_eq:
            raise EqError
        return super().__eq__(other)


class HaskKeyCrasher:
    def __init__(self, *, error_on_hash=False, error_on_eq=False):
        self.error_on_hash = error_on_hash
        self.error_on_eq = error_on_eq

    def __enter__(self):
        if HashKey._crasher is not None:
            raise RuntimeError('cannot nest crashers')
        HashKey._crasher = self

    def __exit__(self, *exc):
        HashKey._crasher = None


class HashingError(Exception):
    pass


class EqError(Exception):
    pass


@unittest.skipIf(hamt is None, '_testinternalcapi.hamt() not available')
class HamtTest(unittest.TestCase):

    def test_hashkey_helper_1(self):
        k1 = HashKey(10, 'aaa')
        k2 = HashKey(10, 'bbb')

        self.assertNotEqual(k1, k2)
        self.assertEqual(hash(k1), hash(k2))

        d = dict()
        d[k1] = 'a'
        d[k2] = 'b'

        self.assertEqual(d[k1], 'a')
        self.assertEqual(d[k2], 'b')

    def test_hamt_basics_1(self):
        h = hamt()
        h = None  

    def test_hamt_basics_2(self):
        h = hamt()
        self.assertEqual(len(h), 0)

        h2 = h.set('a', 'b')
        self.assertIsNot(h, h2)
        self.assertEqual(len(h), 0)
        self.assertEqual(len(h2), 1)

        self.assertIsNone(h.get('a'))
        self.assertEqual(h.get('a', 42), 42)

        self.assertEqual(h2.get('a'), 'b')

        h3 = h2.set('b', 10)
        self.assertIsNot(h2, h3)
        self.assertEqual(len(h), 0)
        self.assertEqual(len(h2), 1)
        self.assertEqual(len(h3), 2)
        self.assertEqual(h3.get('a'), 'b')
        self.assertEqual(h3.get('b'), 10)

        self.assertIsNone(h.get('b'))
        self.assertIsNone(h2.get('b'))

        self.assertIsNone(h.get('a'))
        self.assertEqual(h2.get('a'), 'b')

        h = h2 = h3 = None

    def test_hamt_basics_3(self):
        h = hamt()
        o = object()
        h1 = h.set('1', o)
        h2 = h1.set('1', o)
        self.assertIs(h1, h2)

    def test_hamt_basics_4(self):
        h = hamt()
        h1 = h.set('key', [])
        h2 = h1.set('key', [])
        self.assertIsNot(h1, h2)
        self.assertEqual(len(h1), 1)
        self.assertEqual(len(h2), 1)
        self.assertIsNot(h1.get('key'), h2.get('key'))

    def test_hamt_collision_1(self):
        k1 = HashKey(10, 'aaa')
        k2 = HashKey(10, 'bbb')
        k3 = HashKey(10, 'ccc')

        h = hamt()
        h2 = h.set(k1, 'a')
        h3 = h2.set(k2, 'b')

        self.assertEqual(h.get(k1), None)
        self.assertEqual(h.get(k2), None)

        self.assertEqual(h2.get(k1), 'a')
        self.assertEqual(h2.get(k2), None)

        self.assertEqual(h3.get(k1), 'a')
        self.assertEqual(h3.get(k2), 'b')

        h4 = h3.set(k2, 'cc')
        h5 = h4.set(k3, 'aa')

        self.assertEqual(h3.get(k1), 'a')
        self.assertEqual(h3.get(k2), 'b')
        self.assertEqual(h4.get(k1), 'a')
        self.assertEqual(h4.get(k2), 'cc')
        self.assertEqual(h4.get(k3), None)
        self.assertEqual(h5.get(k1), 'a')
        self.assertEqual(h5.get(k2), 'cc')
        self.assertEqual(h5.get(k2), 'cc')
        self.assertEqual(h5.get(k3), 'aa')

        self.assertEqual(len(h), 0)
        self.assertEqual(len(h2), 1)
        self.assertEqual(len(h3), 2)
        self.assertEqual(len(h4), 2)
        self.assertEqual(len(h5), 3)

    def test_hamt_collision_3(self):
        
        

        C = HashKey(0b10000000_00000000_00000000_00000000, 'C')
        D = HashKey(0b10000000_00000000_00000000_00000000, 'D')

        E = HashKey(0b00000000_00000000_00000000_00000000, 'E')

        h = hamt()
        h = h.set(C, 'C')
        h = h.set(D, 'D')
        h = h.set(E, 'E')

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        self.assertEqual({k.name for k in h.keys()}, {'C', 'D', 'E'})

    @support.requires_resource('cpu')
    def test_hamt_stress(self):
        COLLECTION_SIZE = 7000
        TEST_ITERS_EVERY = 647
        CRASH_HASH_EVERY = 97
        CRASH_EQ_EVERY = 11
        RUN_XTIMES = 3

        for _ in range(RUN_XTIMES):
            h = hamt()
            d = dict()

            for i in range(COLLECTION_SIZE):
                key = KeyStr(i)

                if not (i % CRASH_HASH_EVERY):
                    with HaskKeyCrasher(error_on_hash=True):
                        with self.assertRaises(HashingError):
                            h.set(key, i)

                h = h.set(key, i)

                if not (i % CRASH_EQ_EVERY):
                    with HaskKeyCrasher(error_on_eq=True):
                        with self.assertRaises(EqError):
                            h.get(KeyStr(i))  

                d[key] = i
                self.assertEqual(len(d), len(h))

                if not (i % TEST_ITERS_EVERY):
                    self.assertEqual(set(h.items()), set(d.items()))
                    self.assertEqual(len(h.items()), len(d.items()))

            self.assertEqual(len(h), COLLECTION_SIZE)

            for key in range(COLLECTION_SIZE):
                self.assertEqual(h.get(KeyStr(key), 'not found'), key)

            keys_to_delete = list(range(COLLECTION_SIZE))
            random.shuffle(keys_to_delete)
            for iter_i, i in enumerate(keys_to_delete):
                key = KeyStr(i)

                if not (iter_i % CRASH_HASH_EVERY):
                    with HaskKeyCrasher(error_on_hash=True):
                        with self.assertRaises(HashingError):
                            h.delete(key)

                if not (iter_i % CRASH_EQ_EVERY):
                    with HaskKeyCrasher(error_on_eq=True):
                        with self.assertRaises(EqError):
                            h.delete(KeyStr(i))

                h = h.delete(key)
                self.assertEqual(h.get(key, 'not found'), 'not found')
                del d[key]
                self.assertEqual(len(d), len(h))

                if iter_i == COLLECTION_SIZE // 2:
                    hm = h
                    dm = d.copy()

                if not (iter_i % TEST_ITERS_EVERY):
                    self.assertEqual(set(h.keys()), set(d.keys()))
                    self.assertEqual(len(h.keys()), len(d.keys()))

            self.assertEqual(len(d), 0)
            self.assertEqual(len(h), 0)

            

            for key in dm:
                self.assertEqual(hm.get(str(key)), dm[key])
            self.assertEqual(len(dm), len(hm))

            for i, key in enumerate(keys_to_delete):
                hm = hm.delete(str(key))
                self.assertEqual(hm.get(str(key), 'not found'), 'not found')
                dm.pop(str(key), None)
                self.assertEqual(len(d), len(h))

                if not (i % TEST_ITERS_EVERY):
                    self.assertEqual(set(h.values()), set(d.values()))
                    self.assertEqual(len(h.values()), len(d.values()))

            self.assertEqual(len(d), 0)
            self.assertEqual(len(h), 0)
            self.assertEqual(list(h.items()), [])

    def test_hamt_delete_1(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(102, 'C')
        D = HashKey(103, 'D')
        E = HashKey(104, 'E')
        Z = HashKey(-100, 'Z')

        Er = HashKey(103, 'Er', error_on_eq_to=D)

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')

        orig_len = len(h)

        
        
        
        
        
        

        h = h.delete(C)
        self.assertEqual(len(h), orig_len - 1)

        with self.assertRaisesRegex(ValueError, 'cannot compare'):
            h.delete(Er)

        h = h.delete(D)
        self.assertEqual(len(h), orig_len - 2)

        h2 = h.delete(Z)
        self.assertIs(h2, h)

        h = h.delete(A)
        self.assertEqual(len(h), orig_len - 3)

        self.assertEqual(h.get(A, 42), 42)
        self.assertEqual(h.get(B), 'b')
        self.assertEqual(h.get(E), 'e')

    def test_hamt_delete_2(self):
        A = HashKey(100, 'A')
        B = HashKey(201001, 'B')
        C = HashKey(101001, 'C')
        D = HashKey(103, 'D')
        E = HashKey(104, 'E')
        Z = HashKey(-100, 'Z')

        Er = HashKey(201001, 'Er', error_on_eq_to=B)

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')

        orig_len = len(h)

        
        
        
        
        
        
        
        

        with self.assertRaisesRegex(ValueError, 'cannot compare'):
            h.delete(Er)

        h = h.delete(Z)
        self.assertEqual(len(h), orig_len)

        h = h.delete(C)
        self.assertEqual(len(h), orig_len - 1)

        h = h.delete(B)
        self.assertEqual(len(h), orig_len - 2)

        h = h.delete(A)
        self.assertEqual(len(h), orig_len - 3)

        self.assertEqual(h.get(D), 'd')
        self.assertEqual(h.get(E), 'e')

        h = h.delete(A)
        h = h.delete(B)
        h = h.delete(D)
        h = h.delete(E)
        self.assertEqual(len(h), 0)

    def test_hamt_delete_3(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(100100, 'C')
        D = HashKey(100100, 'D')
        E = HashKey(104, 'E')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')

        orig_len = len(h)

        
        
        
        
        
        
        
        
        
        

        h = h.delete(A)
        self.assertEqual(len(h), orig_len - 1)

        h = h.delete(E)
        self.assertEqual(len(h), orig_len - 2)

        self.assertEqual(h.get(C), 'c')
        self.assertEqual(h.get(B), 'b')

    def test_hamt_delete_4(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(100100, 'C')
        D = HashKey(100100, 'D')
        E = HashKey(100100, 'E')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')

        orig_len = len(h)

        
        
        
        
        
        
        
        
        
        

        h = h.delete(D)
        self.assertEqual(len(h), orig_len - 1)

        h = h.delete(E)
        self.assertEqual(len(h), orig_len - 2)

        h = h.delete(C)
        self.assertEqual(len(h), orig_len - 3)

        h = h.delete(A)
        self.assertEqual(len(h), orig_len - 4)

        h = h.delete(B)
        self.assertEqual(len(h), 0)

    def test_hamt_delete_5(self):
        h = hamt()

        keys = []
        for i in range(17):
            key = HashKey(i, str(i))
            keys.append(key)
            h = h.set(key, f'val-{i}')

        collision_key16 = HashKey(16, '18')
        h = h.set(collision_key16, 'collision')

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        self.assertEqual(len(h), 18)

        h = h.delete(keys[2])
        self.assertEqual(len(h), 17)

        h = h.delete(collision_key16)
        self.assertEqual(len(h), 16)
        h = h.delete(keys[16])
        self.assertEqual(len(h), 15)

        h = h.delete(keys[1])
        self.assertEqual(len(h), 14)
        h = h.delete(keys[1])
        self.assertEqual(len(h), 14)

        for key in keys:
            h = h.delete(key)
        self.assertEqual(len(h), 0)

    def test_hamt_items_1(self):
        A = HashKey(100, 'A')
        B = HashKey(201001, 'B')
        C = HashKey(101001, 'C')
        D = HashKey(103, 'D')
        E = HashKey(104, 'E')
        F = HashKey(110, 'F')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')
        h = h.set(F, 'f')

        it = h.items()
        self.assertEqual(
            set(list(it)),
            {(A, 'a'), (B, 'b'), (C, 'c'), (D, 'd'), (E, 'e'), (F, 'f')})

    def test_hamt_items_2(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(100100, 'C')
        D = HashKey(100100, 'D')
        E = HashKey(100100, 'E')
        F = HashKey(110, 'F')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')
        h = h.set(F, 'f')

        it = h.items()
        self.assertEqual(
            set(list(it)),
            {(A, 'a'), (B, 'b'), (C, 'c'), (D, 'd'), (E, 'e'), (F, 'f')})

    def test_hamt_keys_1(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(100100, 'C')
        D = HashKey(100100, 'D')
        E = HashKey(100100, 'E')
        F = HashKey(110, 'F')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(B, 'b')
        h = h.set(C, 'c')
        h = h.set(D, 'd')
        h = h.set(E, 'e')
        h = h.set(F, 'f')

        self.assertEqual(set(list(h.keys())), {A, B, C, D, E, F})
        self.assertEqual(set(list(h)), {A, B, C, D, E, F})

    def test_hamt_items_3(self):
        h = hamt()
        self.assertEqual(len(h.items()), 0)
        self.assertEqual(list(h.items()), [])

    def test_hamt_eq_1(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')
        C = HashKey(100100, 'C')
        D = HashKey(100100, 'D')
        E = HashKey(120, 'E')

        h1 = hamt()
        h1 = h1.set(A, 'a')
        h1 = h1.set(B, 'b')
        h1 = h1.set(C, 'c')
        h1 = h1.set(D, 'd')

        h2 = hamt()
        h2 = h2.set(A, 'a')

        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.set(B, 'b')
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.set(C, 'c')
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.set(D, 'd2')
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.set(D, 'd')
        self.assertTrue(h1 == h2)
        self.assertFalse(h1 != h2)

        h2 = h2.set(E, 'e')
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.delete(D)
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

        h2 = h2.set(E, 'd')
        self.assertFalse(h1 == h2)
        self.assertTrue(h1 != h2)

    def test_hamt_eq_2(self):
        A = HashKey(100, 'A')
        Er = HashKey(100, 'Er', error_on_eq_to=A)

        h1 = hamt()
        h1 = h1.set(A, 'a')

        h2 = hamt()
        h2 = h2.set(Er, 'a')

        with self.assertRaisesRegex(ValueError, 'cannot compare'):
            h1 == h2

        with self.assertRaisesRegex(ValueError, 'cannot compare'):
            h1 != h2

    def test_hamt_gc_1(self):
        A = HashKey(100, 'A')

        h = hamt()
        h = h.set(0, 0)  
        ref = weakref.ref(h)

        a = []
        a.append(a)
        a.append(h)
        b = []
        a.append(b)
        b.append(a)
        h = h.set(A, b)

        del h, a, b

        gc.collect()
        gc.collect()
        gc.collect()

        self.assertIsNone(ref())

    def test_hamt_gc_2(self):
        A = HashKey(100, 'A')
        B = HashKey(101, 'B')

        h = hamt()
        h = h.set(A, 'a')
        h = h.set(A, h)

        ref = weakref.ref(h)
        hi = h.items()
        next(hi)

        del h, hi

        gc.collect()
        gc.collect()
        gc.collect()

        self.assertIsNone(ref())

    def test_hamt_in_1(self):
        A = HashKey(100, 'A')
        AA = HashKey(100, 'A')

        B = HashKey(101, 'B')

        h = hamt()
        h = h.set(A, 1)

        self.assertTrue(A in h)
        self.assertFalse(B in h)

        with self.assertRaises(EqError):
            with HaskKeyCrasher(error_on_eq=True):
                AA in h

        with self.assertRaises(HashingError):
            with HaskKeyCrasher(error_on_hash=True):
                AA in h

    def test_hamt_getitem_1(self):
        A = HashKey(100, 'A')
        AA = HashKey(100, 'A')

        B = HashKey(101, 'B')

        h = hamt()
        h = h.set(A, 1)

        self.assertEqual(h[A], 1)
        self.assertEqual(h[AA], 1)

        with self.assertRaises(KeyError):
            h[B]

        with self.assertRaises(EqError):
            with HaskKeyCrasher(error_on_eq=True):
                h[AA]

        with self.assertRaises(HashingError):
            with HaskKeyCrasher(error_on_hash=True):
                h[AA]


if __name__ == "__main__":
    unittest.main()