@@ -270,14 +270,9 @@ async def release(self, *, permanent=True):
270
270
271
271
"""
272
272
if permanent and self ._stack is not None :
273
- for i in range (len (self ._stack )):
274
- if self ._stack [- 1 ].gino_conn is self :
275
- dbapi_conn = self ._stack .pop ()
276
- self ._stack .rotate (- i )
277
- await dbapi_conn .release (True )
278
- break
279
- else :
280
- self ._stack .rotate ()
273
+ dbapi_conn = self ._stack .remove (lambda x : x .gino_conn is self )
274
+ if dbapi_conn :
275
+ await dbapi_conn .release (True )
281
276
else :
282
277
raise ValueError ('This connection is already released.' )
283
278
else :
@@ -493,6 +488,39 @@ async def prepare(self, clause):
493
488
clause , (_bypass_no_param ,), {}).prepare (clause )
494
489
495
490
491
+ class _ContextualStack :
492
+ __slots__ = ('_ctx' , '_stack' )
493
+
494
+ def __init__ (self , ctx ):
495
+ self ._ctx = ctx
496
+ self ._stack = ctx .get ()
497
+ if self ._stack is None :
498
+ self ._stack = collections .deque ()
499
+ ctx .set (self ._stack )
500
+
501
+ def __bool__ (self ):
502
+ return bool (self ._stack )
503
+
504
+ @property
505
+ def top (self ):
506
+ return self ._stack [- 1 ]
507
+
508
+ def push (self , value ):
509
+ self ._stack .append (value )
510
+
511
+ def remove (self , checker ):
512
+ for i in range (len (self ._stack )):
513
+ if checker (self ._stack [- 1 ]):
514
+ rv = self ._stack .pop ()
515
+ if self ._stack :
516
+ self ._stack .rotate (- i )
517
+ else :
518
+ self ._ctx .set (None )
519
+ return rv
520
+ else :
521
+ self ._stack .rotate (1 )
522
+
523
+
496
524
class GinoEngine :
497
525
"""
498
526
Connects a :class:`~.dialects.base.Pool` and
@@ -522,7 +550,7 @@ def __init__(self, dialect, pool, loop,
522
550
self ._dialect = dialect
523
551
self ._pool = pool
524
552
self ._loop = loop
525
- self ._ctx = ContextVar ('gino' )
553
+ self ._ctx = ContextVar ('gino' , default = None )
526
554
527
555
@property
528
556
def dialect (self ):
@@ -608,14 +636,10 @@ def acquire(self, *, timeout=None, reuse=False, lazy=False, reusable=True):
608
636
self ._acquire , timeout , reuse , lazy , reusable ))
609
637
610
638
async def _acquire (self , timeout , reuse , lazy , reusable ):
611
- try :
612
- stack = self ._ctx .get ()
613
- except LookupError :
614
- stack = collections .deque ()
615
- self ._ctx .set (stack )
639
+ stack = _ContextualStack (self ._ctx )
616
640
if reuse and stack :
617
641
dbapi_conn = _ReusingDBAPIConnection (self ._dialect .cursor_cls ,
618
- stack [ - 1 ] )
642
+ stack . top )
619
643
reusable = False
620
644
else :
621
645
dbapi_conn = _DBAPIConnection (self ._dialect .cursor_cls , self ._pool )
@@ -626,7 +650,7 @@ async def _acquire(self, timeout, reuse, lazy, reusable):
626
650
if not lazy :
627
651
await dbapi_conn .acquire (timeout = timeout )
628
652
if reusable :
629
- stack .append (dbapi_conn )
653
+ stack .push (dbapi_conn )
630
654
return rv
631
655
632
656
@property
@@ -638,10 +662,9 @@ def current_connection(self):
638
662
:return: :class:`.GinoConnection`
639
663
640
664
"""
641
- try :
642
- return self ._ctx .get ()[- 1 ].gino_conn
643
- except (LookupError , IndexError ):
644
- pass
665
+ stack = self ._ctx .get ()
666
+ if stack :
667
+ return stack [- 1 ].gino_conn
645
668
646
669
async def close (self ):
647
670
"""
0 commit comments