def test_adapt_bytes(self): snowman = u"\u2603" self.conn.set_client_encoding('utf8') a = psycopg2.extensions.QuotedString(snowman.encode('utf8')) a.prepare(self.conn) q = a.getquoted() self.assert_(q in (b("'\xe2\x98\x83'"), b("E'\xe2\x98\x83'")), q)
def getquoted(self): if self.name is None: raise NotImplementedError( 'RangeAdapter must be subclassed overriding its name ' 'or the getquoted() method') r = self.adapted if r.isempty: return b("'empty'::" + self.name) if r.lower is not None: a = adapt(r.lower) if hasattr(a, 'prepare'): a.prepare(self._conn) lower = a.getquoted() else: lower = b'NULL' if r.upper is not None: a = adapt(r.upper) if hasattr(a, 'prepare'): a.prepare(self._conn) upper = a.getquoted() else: upper = b'NULL' return b(self.name + '(') + lower + b', ' + upper \ + b(", '%s')" % r._bounds)
def test_mogrify_unicode(self): conn = self.conn cur = conn.cursor() # test consistency between execute and mogrify. # unicode query containing only ascii data cur.execute(u"SELECT 'foo';") self.assertEqual('foo', cur.fetchone()[0]) self.assertEqual(b("SELECT 'foo';"), cur.mogrify(u"SELECT 'foo';")) conn.set_client_encoding('UTF8') snowman = u"\u2603" # unicode query with non-ascii data cur.execute(u"SELECT '%s';" % snowman) self.assertEqual(snowman.encode('utf8'), b(cur.fetchone()[0])) self.assertEqual(("SELECT '%s';" % snowman).encode('utf8'), cur.mogrify(u"SELECT '%s';" % snowman).replace(b("E'"), b("'"))) # unicode args cur.execute("SELECT %s;", (snowman,)) self.assertEqual(snowman.encode("utf-8"), b(cur.fetchone()[0])) self.assertEqual(("SELECT '%s';" % snowman).encode('utf8'), cur.mogrify("SELECT %s;", (snowman,)).replace(b("E'"), b("'"))) # unicode query and args cur.execute(u"SELECT %s;", (snowman,)) self.assertEqual(snowman.encode("utf-8"), b(cur.fetchone()[0])) self.assertEqual(("SELECT '%s';" % snowman).encode('utf8'), cur.mogrify(u"SELECT %s;", (snowman,)).replace(b("E'"), b("'")))
def _getquoted_9(self): """Use the hstore(text[], text[]) function.""" if not self.wrapped: return b("''::hstore") k = _ext.adapt(self.wrapped.keys()) k.prepare(self.conn) v = _ext.adapt(self.wrapped.values()) v.prepare(self.conn) return b("hstore(") + k.getquoted() + b(", ") + v.getquoted() + b(")")
def test_read_binary(self): lo = self.conn.lobject() length = lo.write(b("some data")) lo.close() lo = self.conn.lobject(lo.oid, "rb") x = lo.read(4) self.assertEqual(type(x), type(b(''))) self.assertEqual(x, b("some")) self.assertEqual(lo.read(), b(" data"))
def adapt_range(pgrange, pyrange): if not isinstance(pyrange, range_): raise ValueError(( "Trying to adapt range {range.__class__.__name__} which does not " "extend base range type.").format(range=pyrange)) if not pyrange: return AsIs("'empty'::" + pgrange) lower = b("NULL") if not pyrange.lower_inf: lower = adapt(pyrange.lower).getquoted() upper = b("NULL") if not pyrange.upper_inf: upper = adapt(pyrange.upper).getquoted() return AsIs(b"".join([ b(pgrange), b("("), lower, b(", "), upper, b(", '"), b("[" if pyrange.lower_inc else "("), b("]" if pyrange.upper_inc else ")"), b("')") ]).decode("utf8"))
def test_set_encoding(self): # Note: this works-ish mostly in case when the standard db connection # we test with is utf8, otherwise the encoding chosen by PQescapeString # may give bad results. from psycopg2.extensions import adapt snowman = u"\u2603" a = adapt(snowman) a.encoding = 'utf8' self.assertEqual(a.encoding, 'utf8') q = a.getquoted() self.assert_(q in (b("'\xe2\x98\x83'"), b("E'\xe2\x98\x83'")), q)
def test_connection_wins_anyway(self): from psycopg2.extensions import adapt snowman = u"\u2603" a = adapt(snowman) a.encoding = 'latin9' self.conn.set_client_encoding('utf8') a.prepare(self.conn) self.assertEqual(a.encoding, 'utf_8') q = a.getquoted() self.assert_(q in (b("'\xe2\x98\x83'"), b("E'\xe2\x98\x83'")), q)
def test_inet_conform(self): from psycopg2.extras import Inet i = Inet("192.168.1.0/24") a = psycopg2.extensions.adapt(i) a.prepare(self.conn) self.assertEqual(filter_scs(self.conn, b("E'192.168.1.0/24'::inet")), a.getquoted()) # adapts ok with unicode too i = Inet(u"192.168.1.0/24") a = psycopg2.extensions.adapt(i) a.prepare(self.conn) self.assertEqual(filter_scs(self.conn, b("E'192.168.1.0/24'::inet")), a.getquoted())
def test_export(self): lo = self.conn.lobject() lo.write(b("some data")) self.tmpdir = tempfile.mkdtemp() filename = os.path.join(self.tmpdir, "data.txt") lo.export(filename) self.assertTrue(os.path.exists(filename)) f = open(filename, "rb") try: self.assertEqual(f.read(), b("some data")) finally: f.close()
def test_none_in_record(self): curs = self.conn.cursor() s = curs.mogrify("SELECT %s;", [(42, None)]) self.assertEqual(b("SELECT (42, NULL);"), s) curs.execute("SELECT %s;", [(42, None)]) d = curs.fetchone()[0] self.assertEqual("(42,)", d)
def test_full_escaped_octal(self): buf = ''.join(("\\%03o" % i) for i in range(256)) rv = self.cast(b(buf)) if sys.version_info[0] < 3: self.assertEqual(rv, ''.join(map(chr, list(range(256))))) else: self.assertEqual(rv, bytes(list(range(256))))
def test_adapt_8(self): if self.conn.server_version >= 90000: return self.skipTest("skipping dict adaptation with PG pre-9 syntax") from psycopg2.extras import HstoreAdapter o = {"a": "1", "b": "'", "c": None} if self.conn.encoding == "UTF8": o["d"] = u"\xe0" a = HstoreAdapter(o) a.prepare(self.conn) q = a.getquoted() self.assert_(q.startswith(b("((")), q) ii = q[1:-1].split(b("||")) ii.sort() self.assertEqual(len(ii), len(o)) self.assertEqual(ii[0], filter_scs(self.conn, b("(E'a' => E'1')"))) self.assertEqual(ii[1], filter_scs(self.conn, b("(E'b' => E'''')"))) self.assertEqual(ii[2], filter_scs(self.conn, b("(E'c' => NULL)"))) if "d" in o: encc = u"\xe0".encode(psycopg2.extensions.encodings[self.conn.encoding]) self.assertEqual(ii[3], filter_scs(self.conn, b("(E'd' => E'") + encc + b("')")))
def test_import(self): self.tmpdir = tempfile.mkdtemp() filename = os.path.join(self.tmpdir, "data.txt") fp = open(filename, "wb") fp.write(b("some data")) fp.close() lo = self.conn.lobject(0, "r", 0, filename) self.assertEqual(lo.read(), "some data")
def test_full_hex(self, upper=False): buf = ''.join(("%02x" % i) for i in range(256)) if upper: buf = buf.upper() buf = '\\x' + buf rv = self.cast(b(buf)) if sys.version_info[0] < 3: self.assertEqual(rv, ''.join(map(chr, list(range(256))))) else: self.assertEqual(rv, bytes(list(range(256))))
def test_read(self): lo = self.conn.lobject() length = lo.write(b("some data")) lo.close() lo = self.conn.lobject(lo.oid) x = lo.read(4) self.assertEqual(type(x), type('')) self.assertEqual(x, "some") self.assertEqual(lo.read(), " data")
def test_mogrify_decimal_explodes(self): # issue #7: explodes on windows with python 2.5 and psycopg 2.2.2 try: from decimal import Decimal except: return conn = self.conn cur = conn.cursor() self.assertEqual(b("SELECT 10.3;"), cur.mogrify("SELECT %s;", (Decimal("10.3"),)))
def test_adapt_subtype_3(self): from psycopg2.extensions import adapt, register_adapter, AsIs class A: pass class B(A): pass register_adapter(A, lambda a: AsIs("a")) try: self.assertEqual(b("a"), adapt(B()).getquoted()) finally: del psycopg2.extensions.adapters[A, psycopg2.extensions.ISQLQuote]
def getquoted(self): if self.name is None: raise NotImplementedError( "RangeAdapter must be subclassed overriding its name " "or the getquoted() method" ) r = self.adapted if r.isempty: return b("'empty'::" + self.name) if r.lower is not None: a = adapt(r.lower) if hasattr(a, "prepare"): a.prepare(self._conn) lower = a.getquoted() else: lower = b("NULL") if r.upper is not None: a = adapt(r.upper) if hasattr(a, "prepare"): a.prepare(self._conn) upper = a.getquoted() else: upper = b("NULL") return b(self.name + "(") + lower + b(", ") + upper + b(", '%s')" % r._bounds)
def test_binary(self): data = b("""some data with \000\013 binary stuff into, 'quotes' and \\ a backslash too. """) if sys.version_info[0] < 3: data += "".join(map(chr, range(256))) else: data += bytes(range(256)) curs = self.conn.cursor() curs.execute("SELECT %s::bytea;", (psycopg2.Binary(data),)) if sys.version_info[0] < 3: res = str(curs.fetchone()[0]) else: res = curs.fetchone()[0].tobytes() if res[0] in (b('x'), ord(b('x'))) and self.conn.server_version >= 90000: return self.skipTest( "bytea broken with server >= 9.0, libpq < 9") self.assertEqual(res, data) self.assert_(not self.conn.notices)
def test_truncate(self): lo = self.conn.lobject() lo.write(b("some data")) lo.close() lo = self.conn.lobject(lo.oid, "w") lo.truncate(4) # seek position unchanged self.assertEqual(lo.tell(), 0) # data truncated self.assertEqual(lo.read(), b("some")) lo.truncate(6) lo.seek(0) # large object extended with zeroes self.assertEqual(lo.read(), b("some\x00\x00")) lo.truncate() lo.seek(0) # large object empty self.assertEqual(lo.read(), b(""))
def test_adapt_most_specific(self): from psycopg2.extensions import adapt, register_adapter, AsIs class A(object): pass class B(A): pass class C(B): pass register_adapter(A, lambda a: AsIs("a")) register_adapter(B, lambda b: AsIs("b")) try: self.assertEqual(b('b'), adapt(C()).getquoted()) finally: del psycopg2.extensions.adapters[A, psycopg2.extensions.ISQLQuote] del psycopg2.extensions.adapters[B, psycopg2.extensions.ISQLQuote]
def test_escaped_mixed(self): import string buf = "".join(("\\%03o" % i) for i in range(32)) buf += string.ascii_letters buf += "".join("\\" + c for c in string.ascii_letters) buf += "\\\\" rv = self.cast(b(buf)) if sys.version_info[0] < 3: tgt = "".join(map(chr, range(32))) + string.ascii_letters * 2 + "\\" else: tgt = bytes(range(32)) + (string.ascii_letters * 2 + "\\").encode("ascii") self.assertEqual(rv, tgt)
def test_escaped_mixed(self): import string buf = ''.join(("\\%03o" % i) for i in range(32)) buf += string.ascii_letters buf += ''.join('\\' + c for c in string.ascii_letters) buf += '\\\\' rv = self.cast(b(buf)) if sys.version_info[0] < 3: tgt = ''.join(map(chr, list(range(32)))) \ + string.ascii_letters * 2 + '\\' else: tgt = bytes(list(range(32))) + \ (string.ascii_letters * 2 + '\\').encode('ascii') self.assertEqual(rv, tgt)
def test_seek_tell(self): lo = self.conn.lobject() length = lo.write(b("some data")) self.assertEqual(lo.tell(), length) lo.close() lo = self.conn.lobject(lo.oid) self.assertEqual(lo.seek(5, 0), 5) self.assertEqual(lo.tell(), 5) self.assertEqual(lo.read(), "data") # SEEK_CUR: relative current location lo.seek(5) self.assertEqual(lo.seek(2, 1), 7) self.assertEqual(lo.tell(), 7) self.assertEqual(lo.read(), "ta") # SEEK_END: relative to end of file self.assertEqual(lo.seek(-2, 2), length - 2) self.assertEqual(lo.read(), "ta")
def test_none_fast_path(self): # the None adapter is not actually invoked in regular adaptation ext = psycopg2.extensions class WonkyAdapter(object): def __init__(self, obj): pass def getquoted(self): return "NOPE!" curs = self.conn.cursor() orig_adapter = ext.adapters[type(None), ext.ISQLQuote] try: ext.register_adapter(type(None), WonkyAdapter) self.assertEqual(ext.adapt(None).getquoted(), "NOPE!") s = curs.mogrify("SELECT %s;", (None,)) self.assertEqual(b("SELECT NULL;"), s) finally: ext.register_adapter(type(None), orig_adapter)
def getquoted(self): r = self.adapted if r.isempty: return b("'empty'") if not r.lower_inf: # not exactly: we are relying that none of these object is really # quoted (they are numbers). Also, I'm lazy and not preparing the # adapter because I assume encoding doesn't matter for these # objects. lower = adapt(r.lower).getquoted().decode("ascii") else: lower = "" if not r.upper_inf: upper = adapt(r.upper).getquoted().decode("ascii") else: upper = "" return ("'%s%s,%s%s'" % (r._bounds[0], lower, upper, r._bounds[1])).encode("ascii")
def getquoted(self): r = self.adapted if r.isempty: return b("'empty'") if not r.lower_inf: # not exactly: we are relying that none of these object is really # quoted (they are numbers). Also, I'm lazy and not preparing the # adapter because I assume encoding doesn't matter for these # objects. lower = adapt(r.lower).getquoted().decode('ascii') else: lower = '' if not r.upper_inf: upper = adapt(r.upper).getquoted().decode('ascii') else: upper = '' return ("'%s%s,%s%s'" % (r._bounds[0], lower, upper, r._bounds[1])).encode('ascii')
def _getquoted_8(self): """Use the operators available in PG pre-9.0.""" if not self.wrapped: return b("''::hstore") adapt = _ext.adapt rv = [] for k, v in self.wrapped.iteritems(): k = adapt(k) k.prepare(self.conn) k = k.getquoted() if v is not None: v = adapt(v) v.prepare(self.conn) v = v.getquoted() else: v = b('NULL') # XXX this b'ing is painfully inefficient! rv.append(b("(") + k + b(" => ") + v + b(")")) return b("(") + b('||').join(rv) + b(")")
def test_write_after_close(self): lo = self.conn.lobject() lo.close() self.assertRaises(psycopg2.InterfaceError, lo.write, b("some data"))
def test_adapt_bytes(self): snowman = u"\u2603" self.conn.set_client_encoding('utf8') a = psycopg2.extensions.QuotedString(snowman.encode('utf8')) a.prepare(self.conn) self.assertEqual(a.getquoted(), b("'\xe2\x98\x83'"))
def testByteaHexCheckFalsePositive(self): # the check \x -> x to detect bad bytea decode # may be fooled if the first char is really an 'x' o1 = psycopg2.Binary(b('x')) o2 = self.execute("SELECT %s::bytea AS foo", (o1,)) self.assertEqual(b('x'), o2[0])
def testArrayMalformed(self): curs = self.conn.cursor() ss = ['', '{', '{}}', '{' * 20 + '}' * 20] for s in ss: self.assertRaises(psycopg2.DataError, psycopg2.extensions.STRINGARRAY, b(s), curs)
def test_blank_hex(self): # Reported as problematic in ticket #48 rv = self.cast(b('\\x')) self.assertEqual(rv, b(''))
def test_blank(self): rv = self.cast(b('')) self.assertEqual(rv, b(''))
def test_open_for_write(self): lo = self.conn.lobject() lo2 = self.conn.lobject(lo.oid, "w") self.assertEqual(lo2.mode[0], "w") lo2.write(b("some data"))
def test_write_after_commit(self): lo = self.conn.lobject() self.lo_oid = lo.oid self.conn.commit() self.assertRaises(psycopg2.ProgrammingError, lo.write, b("some data"))
def getquoted(self): return b("'%s'::uuid" % self._uuid)
def test_write(self): lo = self.conn.lobject() self.assertEqual(lo.write(b("some data")), len("some data"))
def getquoted(self): obj = _A(self.addr) if hasattr(obj, 'prepare'): obj.prepare(self._conn) return obj.getquoted() + b("::inet")
def filter_scs(conn, s): if conn.get_parameter_status("standard_conforming_strings") == 'off': return s else: return s.replace(b("E'"), b("'"))
def test_adapt_9(self): if self.conn.server_version < 90000: return self.skipTest("skipping dict adaptation with PG 9 syntax") from psycopg2.extras import HstoreAdapter o = {'a': '1', 'b': "'", 'c': None} if self.conn.encoding == 'UTF8': o['d'] = u'\xe0' a = HstoreAdapter(o) a.prepare(self.conn) q = a.getquoted() m = re.match(b(r'hstore\(ARRAY\[([^\]]+)\], ARRAY\[([^\]]+)\]\)'), q) self.assert_(m, repr(q)) kk = m.group(1).split(b(", ")) vv = m.group(2).split(b(", ")) ii = zip(kk, vv) ii.sort() def f(*args): return tuple([filter_scs(self.conn, s) for s in args]) self.assertEqual(len(ii), len(o)) self.assertEqual(ii[0], f(b("E'a'"), b("E'1'"))) self.assertEqual(ii[1], f(b("E'b'"), b("E''''"))) self.assertEqual(ii[2], f(b("E'c'"), b("NULL"))) if 'd' in o: encc = u'\xe0'.encode( psycopg2.extensions.encodings[self.conn.encoding]) self.assertEqual(ii[3], f(b("E'd'"), b("E'") + encc + b("'")))
def test_encoding_default(self): from psycopg2.extensions import adapt a = adapt("hello") self.assertEqual(a.encoding, 'latin1') self.assertEqual(a.getquoted(), b("'hello'"))