14
14
import urllib .parse
15
15
16
16
from . import cursor
17
+ from . import exceptions
17
18
from . import introspection
18
19
from . import prepared_stmt
19
20
from . import protocol
20
21
from . import serverversion
21
22
from . import transaction
22
23
23
24
24
- class Connection :
25
+ class ConnectionMeta (type ):
26
+
27
+ def __instancecheck__ (cls , instance ):
28
+ mro = type (instance ).__mro__
29
+ return Connection in mro or _ConnectionProxy in mro
30
+
31
+
32
+ class Connection (metaclass = ConnectionMeta ):
25
33
"""A representation of a database session.
26
34
27
35
Connections are created by calling :func:`~asyncpg.connection.connect`.
@@ -32,7 +40,7 @@ class Connection:
32
40
'_stmt_cache_max_size' , '_stmt_cache' , '_stmts_to_close' ,
33
41
'_addr' , '_opts' , '_command_timeout' , '_listeners' ,
34
42
'_server_version' , '_server_caps' , '_intro_query' ,
35
- '_reset_query' )
43
+ '_reset_query' , '_proxy' )
36
44
37
45
def __init__ (self , protocol , transport , loop , addr , opts , * ,
38
46
statement_cache_size , command_timeout ):
@@ -70,6 +78,7 @@ def __init__(self, protocol, transport, loop, addr, opts, *,
70
78
self ._intro_query = introspection .INTRO_LOOKUP_TYPES
71
79
72
80
self ._reset_query = None
81
+ self ._proxy = None
73
82
74
83
async def add_listener (self , channel , callback ):
75
84
"""Add a listener for Postgres notifications.
@@ -478,9 +487,18 @@ def _notify(self, pid, channel, payload):
478
487
if channel not in self ._listeners :
479
488
return
480
489
490
+ if self ._proxy is None :
491
+ con_ref = self
492
+ else :
493
+ # `_proxy` is not None when the connection is a member
494
+ # of a connection pool. Which means that the user is working
495
+ # with a PooledConnectionProxy instance, and expects to see it
496
+ # (and not the actual Connection) in their event callbacks.
497
+ con_ref = self ._proxy
498
+
481
499
for cb in self ._listeners [channel ]:
482
500
try :
483
- cb (self , pid , channel , payload )
501
+ cb (con_ref , pid , channel , payload )
484
502
except Exception as ex :
485
503
self ._loop .call_exception_handler ({
486
504
'message' : 'Unhandled exception in asyncpg notification '
@@ -517,6 +535,14 @@ def _get_reset_query(self):
517
535
518
536
return _reset_query
519
537
538
+ def _set_proxy (self , proxy ):
539
+ if self ._proxy is not None and proxy is not None :
540
+ # Should not happen unless there is a bug in `Pool`.
541
+ raise exceptions .InterfaceError (
542
+ 'internal asyncpg error: connection is already proxied' )
543
+
544
+ self ._proxy = proxy
545
+
520
546
521
547
async def connect (dsn = None , * ,
522
548
host = None , port = None ,
@@ -526,7 +552,7 @@ async def connect(dsn=None, *,
526
552
timeout = 60 ,
527
553
statement_cache_size = 100 ,
528
554
command_timeout = None ,
529
- connection_class = Connection ,
555
+ __connection_class__ = Connection ,
530
556
** opts ):
531
557
"""A coroutine to establish a connection to a PostgreSQL server.
532
558
@@ -564,11 +590,7 @@ async def connect(dsn=None, *,
564
590
:param float command_timeout: the default timeout for operations on
565
591
this connection (the default is no timeout).
566
592
567
- :param builtins.type connection_class: A class used to represent
568
- the connection.
569
- Defaults to :class:`~asyncpg.connection.Connection`.
570
-
571
- :return: A *connection_class* instance.
593
+ :return: A :class:`~asyncpg.connection.Connection` instance.
572
594
573
595
Example:
574
596
@@ -582,10 +604,6 @@ async def connect(dsn=None, *,
582
604
... print(types)
583
605
>>> asyncio.get_event_loop().run_until_complete(run())
584
606
[<Record typname='bool' typnamespace=11 ...
585
-
586
-
587
- .. versionadded:: 0.10.0
588
- *connection_class* argument.
589
607
"""
590
608
if loop is None :
591
609
loop = asyncio .get_event_loop ()
@@ -629,13 +647,18 @@ async def connect(dsn=None, *,
629
647
tr .close ()
630
648
raise
631
649
632
- con = connection_class (pr , tr , loop , addr , opts ,
633
- statement_cache_size = statement_cache_size ,
634
- command_timeout = command_timeout )
650
+ con = __connection_class__ (pr , tr , loop , addr , opts ,
651
+ statement_cache_size = statement_cache_size ,
652
+ command_timeout = command_timeout )
635
653
pr .set_connection (con )
636
654
return con
637
655
638
656
657
+ class _ConnectionProxy :
658
+ # Base class to enable `isinstance(Connection)` check.
659
+ __slots__ = ()
660
+
661
+
639
662
def _parse_connect_params (* , dsn , host , port , user ,
640
663
password , database , opts ):
641
664
0 commit comments