/usr/lib/python3/dist-packages/skytools/quoting.py is in python3-skytools 3.3-2.
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 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | # quoting.py
"""Various helpers for string quoting/unquoting."""
from __future__ import division, absolute_import, print_function
import re
import json
try:
from skytools._cquoting import (db_urldecode, db_urlencode, quote_bytea_raw,
quote_copy, quote_literal, unescape, unquote_literal)
except ImportError:
from skytools._pyquoting import (db_urldecode, db_urlencode, quote_bytea_raw,
quote_copy, quote_literal, unescape, unquote_literal)
__all__ = [
# _pyqoting / _cquoting
"db_urldecode", "db_urlencode", "quote_bytea_raw",
"quote_copy", "quote_literal", "unescape", "unquote_literal",
# local
"quote_bytea_literal", "quote_bytea_copy", "quote_statement",
"quote_ident", "quote_fqident", "quote_json", "unescape_copy",
"unquote_ident", "unquote_fqident",
"json_encode", "json_decode",
"make_pgarray",
]
#
# SQL quoting
#
def quote_bytea_literal(s):
"""Quote bytea for regular SQL."""
return quote_literal(quote_bytea_raw(s))
def quote_bytea_copy(s):
"""Quote bytea for COPY."""
return quote_copy(quote_bytea_raw(s))
def quote_statement(sql, dict_or_list):
"""Quote whole statement.
Data values are taken from dict or list or tuple.
"""
if hasattr(dict_or_list, 'items'):
qdict = {}
for k, v in dict_or_list.items():
qdict[k] = quote_literal(v)
return sql % qdict
else:
qvals = [quote_literal(v) for v in dict_or_list]
return sql % tuple(qvals)
# reserved keywords (RESERVED_KEYWORD + TYPE_FUNC_NAME_KEYWORD)
_ident_kwmap = {
"all":1, "analyse":1, "analyze":1, "and":1, "any":1, "array":1, "as":1,
"asc":1, "asymmetric":1, "authorization":1, "between":1, "binary":1, "both":1, "case":1,
"cast":1, "check":1, "collate":1, "collation":1, "column":1, "concurrently":1,
"constraint":1, "create":1, "cross":1, "current_catalog":1, "current_date":1,
"current_role":1, "current_schema":1, "current_time":1, "current_timestamp":1,
"current_user":1, "default":1, "deferrable":1, "desc":1, "distinct":1,
"do":1, "else":1, "end":1, "errors":1, "except":1, "false":1, "fetch":1,
"for":1, "foreign":1, "freeze":1, "from":1, "full":1, "grant":1, "group":1,
"having":1, "ilike":1, "in":1, "initially":1, "inner":1, "intersect":1,
"into":1, "is":1, "isnull":1, "join":1, "lateral":1, "leading":1, "left":1,
"like":1, "limit":1, "localtime":1, "localtimestamp":1, "natural":1, "new":1,
"not":1, "notnull":1, "null":1, "off":1, "offset":1, "old":1, "on":1, "only":1,
"or":1, "order":1, "outer":1, "over":1, "overlaps":1, "placing":1, "primary":1,
"references":1, "returning":1, "right":1, "select":1, "session_user":1,
"similar":1, "some":1, "symmetric":1, "table":1, "tablesample":1, "then":1, "to":1, "trailing":1,
"true":1, "union":1, "unique":1, "user":1, "using":1, "variadic":1, "verbose":1,
"when":1, "where":1, "window":1, "with":1,
}
_ident_bad = re.compile(r"[^a-z0-9_]|^[0-9]")
def quote_ident(s):
"""Quote SQL identifier.
If is checked against weird symbols and keywords.
"""
if _ident_bad.search(s) or s in _ident_kwmap:
s = '"%s"' % s.replace('"', '""')
elif not s:
return '""'
return s
def quote_fqident(s):
"""Quote fully qualified SQL identifier.
The '.' is taken as namespace separator and
all parts are quoted separately
Example:
>>> quote_fqident('tbl')
'public.tbl'
>>> quote_fqident('Baz.Foo.Bar')
'"Baz"."Foo.Bar"'
"""
tmp = s.split('.', 1)
if len(tmp) == 1:
return 'public.' + quote_ident(s)
return '.'.join([quote_ident(name) for name in tmp])
#
# quoting for JSON strings
#
_jsre = re.compile(r'[\x00-\x1F\\/"]')
_jsmap = {
"\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r",
"\t": "\\t", "\\": "\\\\", '"': '\\"',
"/": "\\/", # to avoid html attacks
}
def _json_quote_char(m):
"""Quote single char."""
c = m.group(0)
try:
return _jsmap[c]
except KeyError:
return r"\u%04x" % ord(c)
def quote_json(s):
"""JSON style quoting."""
if s is None:
return "null"
return '"%s"' % _jsre.sub(_json_quote_char, s)
def unescape_copy(val):
r"""Removes C-style escapes, also converts "\N" to None.
Example:
>>> unescape_copy(r'baz\tfo\'o')
"baz\tfo'o"
>>> unescape_copy(r'\N') is None
True
"""
if val == r"\N":
return None
return unescape(val)
def unquote_ident(val):
"""Unquotes possibly quoted SQL identifier.
>>> unquote_ident('Foo')
'foo'
>>> unquote_ident('"Wei "" rd"')
'Wei " rd'
"""
if len(val) > 1 and val[0] == '"' and val[-1] == '"':
return val[1:-1].replace('""', '"')
if val.find('"') > 0:
raise Exception('unsupported syntax')
return val.lower()
def unquote_fqident(val):
"""Unquotes fully-qualified possibly quoted SQL identifier.
>>> unquote_fqident('foo')
'foo'
>>> unquote_fqident('"Foo"."Bar "" z"')
'Foo.Bar " z'
"""
tmp = val.split('.', 1)
return '.'.join([unquote_ident(i) for i in tmp])
def json_encode(val=None, **kwargs):
"""Creates JSON string from Python object.
>>> json_encode({'a': 1})
'{"a": 1}'
>>> json_encode('a')
'"a"'
>>> json_encode(['a'])
'["a"]'
>>> json_encode(a=1)
'{"a": 1}'
"""
return json.dumps(val or kwargs)
def json_decode(s):
"""Parses JSON string into Python object.
>>> json_decode('[1]')
[1]
"""
return json.loads(s)
#
# Create Postgres array
#
# any chars not in "good" set? main bad ones: [ ,{}\"]
_pgarray_bad_rx = r"[^0-9a-z_.%&=()<>*/+-]"
_pgarray_bad_rc = None
def _quote_pgarray_elem(s):
if s is None:
return 'NULL'
s = str(s)
if _pgarray_bad_rc.search(s):
s = s.replace('\\', '\\\\')
return '"' + s.replace('"', r'\"') + '"'
elif not s:
return '""'
return s
def make_pgarray(lst):
r"""Formats Python list as Postgres array.
Reverse of parse_pgarray().
>>> make_pgarray([])
'{}'
>>> make_pgarray(['foo_3',1,'',None])
'{foo_3,1,"",NULL}'
>>> make_pgarray([None,',','\\',"'",'"',"{","}",'_'])
'{NULL,",","\\\\","\'","\\"","{","}",_}'
"""
global _pgarray_bad_rc
if _pgarray_bad_rc is None:
_pgarray_bad_rc = re.compile(_pgarray_bad_rx)
items = [_quote_pgarray_elem(v) for v in lst]
return '{' + ','.join(items) + '}'
|