/usr/lib/python3/dist-packages/postgresql/python/element.py is in python3-postgresql 1.1.0-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | ##
# .python.element
##
import os
from abc import ABCMeta, abstractproperty, abstractmethod
from .string import indent
from .decorlib import propertydoc
class RecursiveFactor(Exception):
'Raised when a factor is ultimately composed of itself'
pass
class Element(object, metaclass = ABCMeta):
"""
The purpose of an element is to provide a general mechanism for specifying
the factors that composed an object. Factors are designated using an
ordered set of strings referencing those significant attributes on the object.
Factors are important for PG-API as it provides the foundation for
collecting the information about the state of the interface that ultimately
led up to an error.
Traceback:
...
postgresql.exceptions.*: <message>
CODE: XX000
CURSOR: <cursor_id>
parameters: (p1, p2, ...)
STATEMENT: <statement_id> <parameter info>
...
string:
<query body>
SYMBOL: get_types
LIBRARY: catalog
...
CONNECTION:
<backend_id> <socket information>
CONNECTOR: [Host]
IRI: pq://user@localhost:5432/database
DRIVER: postgresql.driver.pq3
"""
@propertydoc
@abstractproperty
def _e_label(self) -> str:
"""
Single-word string describing the kind of element.
For instance, `postgresql.api.Statement`'s _e_label is 'STATEMENT'.
Usually, this is set directly on the class itself, and is a shorter
version of the class's name.
"""
@propertydoc
@abstractproperty
def _e_factors(self) -> ():
"""
The attribute names of the objects that contributed to the creation of
this object.
The ordering is significant. The first factor is the prime factor.
"""
@abstractmethod
def _e_metas(self) -> [(str, object)]:
"""
Return an iterable to key-value pairs that provide useful descriptive
information about an attribute.
Factors on metas are not checked. They are expected to be primitives.
If there are no metas, the str() of the object will be used to represent
it.
"""
class ElementSet(Element, set):
"""
An ElementSet is a set of Elements that can be used as an individual factor.
In situations where a single factor is composed of multiple elements where
each has no significance over the other, this Element can be used represent
that fact.
Importantly, it provides the set metadata so that the appropriate information
will be produced in element tracebacks.
"""
_e_label = 'SET'
_e_factors = ()
__slots__ = ()
def _e_metas(self):
yield (None, len(self))
for x in self:
yield (None, '--')
yield (None, format_element(x))
def prime_factor(obj):
'get the primary factor on the `obj`, returns None if none.'
f = getattr(obj, '_e_factors', None)
if f:
return f[0], getattr(obj, f[0], None)
def prime_factors(obj):
"""
Yield out the sequence of primary factors of the given object.
"""
visited = set((obj,))
ef = getattr(obj, '_e_factors', None)
if not ef:
return
fn = ef[0]
e = getattr(obj, fn, None)
if e in visited:
raise RecursiveFactor(obj, e)
visited.add(e)
yield fn, e
while e is not None:
ef = getattr(obj, '_e_factors', None)
fn = ef[0]
e = getattr(e, fn, None)
if e in visited:
raise RecursiveFactor(obj, e)
visited.add(e)
yield fn, e
def format_element(obj, coverage = ()):
'format the given element with its factors and metadata into a readable string'
# if it's not an Element, all there is to return is str(obj)
if obj in coverage:
raise RecursiveFactor(coverage)
coverage = coverage + (obj,)
if not isinstance(obj, Element):
if obj is None:
return 'None'
return str(obj)
# The description of `obj` is built first.
# formal element, get metas first.
nolead = False
metas = []
for key, val in obj._e_metas():
m = ""
if val is None:
sval = 'None'
else:
sval = str(val)
pre = ' '
if key is not None:
m += key + ':'
if (len(sval) > 70 or os.linesep in sval):
pre = os.linesep
sval = indent(sval)
else:
# if the key is None, it is intended to be inlined.
nolead = True
pre = ''
m += pre + sval.rstrip()
metas.append(m)
factors = []
for att in obj._e_factors[1:]:
m = ""
f = getattr(obj, att)
# if the object has a label, use the label
m += att + ':'
sval = format_element(f, coverage = coverage)
if len(sval) > 70 or os.linesep in sval:
m += os.linesep + indent(sval)
else:
m += ' ' + sval
factors.append(m)
mtxt = os.linesep.join(metas)
ftxt = os.linesep.join(factors)
if mtxt:
mtxt = indent(mtxt)
if ftxt:
ftxt = indent(ftxt)
s = mtxt + ftxt
if nolead is True:
# metas started with a `None` key.
s = ' ' + s.lstrip()
else:
s = os.linesep + s
s = obj._e_label + ':' + s.rstrip()
# and resolve the next prime
pf = prime_factor(obj)
if pf is not None:
factor_name, prime = pf
factor = format_element(prime, coverage = coverage)
if getattr(prime, '_e_label', None) is not None:
# if the factor has a label, then it will be
# included in the format_element output, and
# thus factor_name is not needed.
factor_name = ''
else:
factor_name += ':'
if len(factor) > 70 or os.linesep in factor:
factor = os.linesep + indent(factor)
else:
factor_name += ' '
s += os.linesep + factor_name + factor
return s
|