Skip to content

Commit 25b12e3

Browse files
author
James William Pye
committed
Fix numerous bugs by getting test.test_driver working.
* __class__ was being set in PS's __del__ causing reference theft until a negative reference count occurred crashing the interpreter. * Make ProcedureLookup more portable(works on 8.0 now). * Bring the ClosedConnection transaction up to interface parity. (asyncs is a method not a tuple) * Fix IP4 connectors, NameError. (referred to AF_INET4, not AF_INET) * Fix postgresql.string. It was using the old iterator protocol(.next() method). Additions: * postgresql.python package providing a location for Python oriented tools. * postgresql.unittest provding a TestCaseWithCluster class. *
1 parent 621d68c commit 25b12e3

19 files changed

Lines changed: 646 additions & 446 deletions

postgresql/api.py

Lines changed: 44 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -23,42 +23,8 @@
2323
import collections
2424
from abc import ABCMeta, abstractproperty, abstractmethod
2525
from operator import methodcaller, itemgetter
26-
27-
class docstr(object):
28-
"""
29-
Simple object that sets the __doc__ attribute to the first parameter and
30-
initializes __annotations__ using keyword arguments.
31-
"""
32-
def __init__(self, doc, **annotations):
33-
self.__doc__ = str(doc)
34-
self.__annotations__ = annotations
35-
36-
def apdoc(ap):
37-
"""
38-
Helper function for extracting an `abstractproperty`'s real documentation.
39-
"""
40-
doc = ""
41-
rstr = ""
42-
if ap.fget:
43-
ret = ap.fget.__annotations__.get('return')
44-
if ret is not None:
45-
rstr = " -> " + repr(ret)
46-
if ap.fget.__doc__:
47-
doc += os.linesep*2 + "GET::" + (os.linesep + ' '*4) + (os.linesep + ' '*4).join(
48-
[x.strip() for x in ap.fget.__doc__.strip().split(os.linesep)]
49-
)
50-
if ap.fset and ap.fset.__doc__:
51-
doc += os.linesep*2 + "SET::" + (os.linesep + ' '*4) + (os.linesep + ' '*4).join(
52-
[x.strip() for x in ap.fset.__doc__.strip().split(os.linesep)]
53-
)
54-
if ap.fdel and ap.fdel.__doc__:
55-
doc += os.linesep*2 + "DELETE::" + (os.linesep + ' '*4) + (os.linesep + ' '*4).join(
56-
[x.strip() for x in ap.fdel.__doc__.strip().split(os.linesep)]
57-
)
58-
ap.__doc__ = "<no documentation>" if not doc else (
59-
"Abstract Property" + rstr + doc
60-
)
61-
return ap
26+
from .python.doc import Doc
27+
from .python.decorlib import propertydoc
6228

6329
class Receptor(collections.Callable):
6430
"""
@@ -136,7 +102,7 @@ class InterfaceElement(metaclass = ABCMeta):
136102
"""
137103
ife_object_title = "<untitled>"
138104

139-
@apdoc
105+
@propertydoc
140106
@abstractproperty
141107
def ife_ancestor(self):
142108
"""
@@ -148,7 +114,7 @@ def ife_ancestor(self):
148114
. State acquisition on error for lineage reporting.
149115
"""
150116

151-
@apdoc
117+
@propertydoc
152118
@abstractproperty
153119
def ife_label(self) -> str:
154120
"""
@@ -265,7 +231,7 @@ def ife_emit(self,
265231
"""
266232
# Don't include ancestors without receptors.
267233
a = [
268-
x for x in self.ifa_ancestry()
234+
x for x in self.ife_ancestry()
269235
if getattr(x, '_ife_receptors', None) is not None
270236
]
271237
if getattr(self, '_ife_receptors', None) is not None:
@@ -386,7 +352,7 @@ def ife_snapshot_text(self):
386352
code = (os.linesep + "CODE: " + self.code) if self.code else ""
387353

388354
sev = details.get('severity')
389-
sevmsg = os.linesep
355+
sevmsg = ""
390356
if sev:
391357
sevmsg = os.linesep + "SEVERITY: " + sev.upper()
392358
detailstr = os.linesep.join((
@@ -399,7 +365,7 @@ def ife_snapshot_text(self):
399365
return self.message + code + sevmsg + detailstr + locstr
400366

401367
def emit(self):
402-
self.snapshot = self.ife_lineage_snapshot_text()
368+
self.snapshot = self.ife_ancestry_snapshot_text()
403369
self.ife_emit(self)
404370

405371
class Cursor(
@@ -423,43 +389,43 @@ class Cursor(
423389
2 : 'LAST',
424390
}
425391

426-
@apdoc
392+
@propertydoc
427393
@abstractproperty
428394
def cursor_id(self) -> str:
429395
"""
430396
The cursor's identifier.
431397
"""
432398

433-
@apdoc
399+
@propertydoc
434400
@abstractproperty
435401
def parameters(self) -> (tuple, None):
436402
"""
437403
The parameters bound to the cursor. `None`, if unknown.
438404
"""
439405

440-
@apdoc
406+
@propertydoc
441407
@abstractproperty
442408
def statement(self) -> ("PreparedStatement", None):
443409
"""
444410
The query object used to create the cursor. `None`, if unknown.
445411
"""
446412

447-
@apdoc
413+
@propertydoc
448414
@abstractproperty
449415
def insensitive(self) -> bool:
450416
"""
451417
Whether or not the cursor is insensitive. Extant versions of PostgreSQL
452418
only support insensitive cursors.
453419
"""
454420

455-
@apdoc
421+
@propertydoc
456422
@abstractproperty
457423
def with_scroll(self) -> bool:
458424
"""
459425
Whether or not the cursor is scrollable.
460426
"""
461427

462-
@apdoc
428+
@propertydoc
463429
@abstractproperty
464430
def with_hold(self) -> bool:
465431
"""
@@ -523,14 +489,14 @@ class PreparedStatement(
523489
"""
524490
ife_label = 'STATEMENT'
525491

526-
@apdoc
492+
@propertydoc
527493
@abstractproperty
528494
def statement_id(self) -> str:
529495
"""
530496
The statment's identifier.
531497
"""
532498

533-
@apdoc
499+
@propertydoc
534500
@abstractproperty
535501
def string(self) -> str:
536502
"""
@@ -664,15 +630,15 @@ class TransactionManager(
664630
"""
665631
ife_label = 'XACT'
666632

667-
@apdoc
633+
@propertydoc
668634
@abstractproperty
669635
def failed(self) -> (bool, None):
670636
"""
671637
bool stating if the current transaction has failed due to an error.
672638
`None` if not in a transaction block.
673639
"""
674640

675-
@apdoc
641+
@propertydoc
676642
@abstractproperty
677643
def depth(self) -> int:
678644
"""
@@ -777,7 +743,7 @@ def rollback_prepared(self, *gids : str):
777743
Rollback the prepared transactions with the given `gid`.
778744
"""
779745

780-
@apdoc
746+
@propertydoc
781747
@abstractproperty
782748
def prepared(self) -> "sequence of prepared transaction identifiers":
783749
"""
@@ -809,7 +775,7 @@ def setpath(self, seq : [str]):
809775
Set the "search_path" setting to the given a sequence of schema names,
810776
[Implementations must properly escape and join the strings]
811777
"""
812-
path = apdoc(abstractproperty(
778+
path = propertydoc(abstractproperty(
813779
getpath, setpath,
814780
doc = """
815781
An interface to a structured ``search_path`` setting:
@@ -945,14 +911,14 @@ class Database(InterfaceElement):
945911
"""
946912
ife_label = 'DATABASE'
947913

948-
@apdoc
914+
@propertydoc
949915
@abstractproperty
950916
def backend_id(self) -> (int, None):
951917
"""
952918
The backend's process identifier.
953919
"""
954920

955-
@apdoc
921+
@propertydoc
956922
@abstractproperty
957923
def version_info(self) -> tuple:
958924
"""
@@ -962,7 +928,7 @@ def version_info(self) -> tuple:
962928
(8, 1, 3, '', 0)
963929
"""
964930

965-
@apdoc
931+
@propertydoc
966932
@abstractproperty
967933
def client_address(self) -> (str, None):
968934
"""
@@ -972,7 +938,7 @@ def client_address(self) -> (str, None):
972938
`None` if unavailable.
973939
"""
974940

975-
@apdoc
941+
@propertydoc
976942
@abstractproperty
977943
def client_port(self) -> (int, None):
978944
"""
@@ -982,23 +948,23 @@ def client_port(self) -> (int, None):
982948
`None` if unavailable.
983949
"""
984950

985-
user = apdoc(abstractproperty(
986-
fget = docstr(
951+
user = propertydoc(abstractproperty(
952+
fget = Doc(
987953
"Give the string returned by ``SELECT current_user``",
988954
**{'return':str}
989955
),
990-
fset = docstr("Pass the given string as a parameter to ``SET ROLE``"),
991-
fdel = docstr("Issue ``RESET ROLE`` to the server"),
956+
fset = Doc("Pass the given string as a parameter to ``SET ROLE``"),
957+
fdel = Doc("Issue ``RESET ROLE`` to the server"),
992958
))
993959

994-
@apdoc
960+
@propertydoc
995961
@abstractproperty
996962
def xact(self) -> TransactionManager:
997963
"""
998964
A `TransactionManager` instance bound to the `Database`.
999965
"""
1000966

1001-
@apdoc
967+
@propertydoc
1002968
@abstractproperty
1003969
def settings(self) -> Settings:
1004970
"""
@@ -1114,15 +1080,15 @@ class Connector(InterfaceElement):
11141080
"""
11151081
ife_label = 'CONNECTOR'
11161082

1117-
@apdoc
1083+
@propertydoc
11181084
@abstractproperty
11191085
def Connection(self) -> "`Connection`":
11201086
"""
11211087
The default `Connection` class that is used.
11221088
This *should* be available on the type object.
11231089
"""
11241090

1125-
@apdoc
1091+
@propertydoc
11261092
@abstractproperty
11271093
def fatal_exception(self) -> Exception:
11281094
"""
@@ -1132,23 +1098,23 @@ def fatal_exception(self) -> Exception:
11321098
indicate if that particular exception is actually fatal.
11331099
"""
11341100

1135-
@apdoc
1101+
@propertydoc
11361102
@abstractproperty
11371103
def timeout_exception(self) -> Exception:
11381104
"""
11391105
The exception raised by the socket when an operation could not be
11401106
completed due to a configured time constraint.
11411107
"""
11421108

1143-
@apdoc
1109+
@propertydoc
11441110
@abstractproperty
11451111
def tryagain_exception(self) -> Exception:
11461112
"""
11471113
The exception raised by the socket when an operation was interrupted, but
11481114
should be tried again.
11491115
"""
11501116

1151-
@apdoc
1117+
@propertydoc
11521118
@abstractproperty
11531119
def tryagain(self, err : Exception) -> bool:
11541120
"""
@@ -1224,15 +1190,15 @@ class Connection(Database):
12241190
"""
12251191
ife_label = 'CONNECTION'
12261192

1227-
@apdoc
1193+
@propertydoc
12281194
@abstractproperty
12291195
def connector(self) -> Connector:
12301196
"""
12311197
The `Connector` instance facilitating the `Connection` object's
12321198
communication and initialization.
12331199
"""
12341200

1235-
@apdoc
1201+
@propertydoc
12361202
@abstractproperty
12371203
def closed(self) -> bool:
12381204
"""
@@ -1271,11 +1237,11 @@ def reconnect(self, *args, **kw) -> None:
12711237
__enter__ = methodcaller('connect')
12721238
def __exit__(self, typ, obj, tb):
12731239
"""
1274-
Closes the connection and returns `True` when an exception is passed in,
1275-
`False` when `None`.
1240+
Closes the connection and returns `False` when an exception is passed in,
1241+
`True` when `None`.
12761242
"""
12771243
self.close()
1278-
return typ is not None
1244+
return typ is None
12791245

12801246
def __context__(self):
12811247
"""
@@ -1333,14 +1299,14 @@ class Installation(InterfaceElement):
13331299
"""
13341300
ife_label = "INSTALLATION"
13351301

1336-
@apdoc
1302+
@propertydoc
13371303
@abstractproperty
13381304
def version(self):
13391305
"""
13401306
A version string consistent with what `SELECT version()` would output.
13411307
"""
13421308

1343-
@apdoc
1309+
@propertydoc
13441310
@abstractproperty
13451311
def version_info(self):
13461312
"""
@@ -1350,7 +1316,7 @@ def version_info(self):
13501316
See `postgresql.versionstring`.
13511317
"""
13521318

1353-
@apdoc
1319+
@propertydoc
13541320
@abstractproperty
13551321
def type(self):
13561322
"""
@@ -1366,7 +1332,7 @@ class Cluster(InterfaceElement):
13661332
ife_label = 'CLUSTER'
13671333
ife_ancestor = None
13681334

1369-
@apdoc
1335+
@propertydoc
13701336
@abstractproperty
13711337
def installation(self) -> Installation:
13721338
"""
@@ -1449,7 +1415,7 @@ def wait_until_stopped(self,
14491415
`postgresql.exceptions.ClusterTimeoutError`.
14501416
"""
14511417

1452-
@apdoc
1418+
@propertydoc
14531419
@abstractproperty
14541420
def settings(self):
14551421
"""

0 commit comments

Comments
 (0)