[Python-modules-commits] [python-vertica] 01/03: Import python-vertica_0.7.3.orig.tar.gz
Jean Baptiste Favre
jbfavre-guest at moszumanska.debian.org
Wed Jun 21 06:29:49 UTC 2017
This is an automated email from the git hooks/post-receive script.
jbfavre-guest pushed a commit to branch master
in repository python-vertica.
commit f5f20028a530f0eb6b52bfc831c4785cdca49e4c
Author: Jean Baptiste Favre <debian at jbfavre.org>
Date: Wed Jun 21 08:09:48 2017 +0200
Import python-vertica_0.7.3.orig.tar.gz
---
setup.py | 2 +-
vertica_python/__init__.py | 2 +-
vertica_python/tests/test_cursor.py | 45 +++++++++++++++++++++++
vertica_python/tests/test_unicode.py | 26 +++++++++++++
vertica_python/vertica/cursor.py | 59 ++++++++++++++++--------------
vertica_python/vertica/messages/message.py | 1 +
6 files changed, 106 insertions(+), 29 deletions(-)
diff --git a/setup.py b/setup.py
index 4823d12..1c5b734 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ opts = ReqOpts(None, 'git')
# version should use the format 'x.x.x' (instead of 'vx.x.x')
setup(
name='vertica-python',
- version='0.7.1',
+ version='0.7.3',
description='A native Python client for the Vertica database.',
author='Justin Berka, Alex Kim',
author_email='justin.berka at gmail.com, alex.kim at uber.com',
diff --git a/vertica_python/__init__.py b/vertica_python/__init__.py
index f90fcd0..57e1df6 100644
--- a/vertica_python/__init__.py
+++ b/vertica_python/__init__.py
@@ -21,7 +21,7 @@ __all__ = ['Connection', 'PROTOCOL_VERSION', 'version_info', 'apilevel', 'thread
'OperationalError', 'ProgrammingError']
# The version number of this library.
-version_info = (0, 7, 1)
+version_info = (0, 7, 3)
__version__ = '.'.join(map(str, version_info))
# The protocol version (3.0.0) implemented in this library.
diff --git a/vertica_python/tests/test_cursor.py b/vertica_python/tests/test_cursor.py
index d76c0b8..8d7dd6c 100644
--- a/vertica_python/tests/test_cursor.py
+++ b/vertica_python/tests/test_cursor.py
@@ -351,3 +351,48 @@ class CursorTestCase(VerticaPythonTestCase):
cur.execute("")
res = cur.fetchall()
self.assertListOfListsEqual(res, [])
+
+
+class TestExecutemany(VerticaPythonTestCase):
+ def setUp(self):
+ self._init_table()
+
+ def tearDown(self):
+ # self._init_table()
+ pass
+
+ def _init_table(self):
+ with self._connect() as conn:
+ cur = conn.cursor()
+ # clean old table
+ cur.execute("DROP TABLE IF EXISTS {0}".format(self._table))
+
+ # create test table
+ cur.execute("""CREATE TABLE {0} (
+ a INT,
+ b VARCHAR(32)
+ )
+ """.format(self._table))
+
+ def _test_executemany(self, table, seq_of_values):
+ with self._connect() as conn:
+ cur = conn.cursor()
+
+ cur.executemany("INSERT INTO {0} (a, b) VALUES (%s, %s)".format(table),
+ seq_of_values)
+ conn.commit()
+
+ cur.execute("SELECT * FROM {0} ORDER BY a ASC, b ASC".format(table))
+
+ # check first select results
+ res1 = cur.fetchall()
+ seq_of_values_to_compare = sorted([list(values) for values in seq_of_values])
+ self.assertListOfListsEqual(res1, seq_of_values_to_compare)
+ self.assertIsNone(cur.fetchone())
+
+ def test_executemany(self):
+ self._test_executemany(self._table, [(1, 'aa'), (2, 'bb')])
+
+ def test_executemany_quoted_path(self):
+ table = '.'.join(['"{}"'.format(s.strip('"')) for s in self._table.split('.')])
+ self._test_executemany(table, [(1, 'aa'), (2, 'bb')])
diff --git a/vertica_python/tests/test_unicode.py b/vertica_python/tests/test_unicode.py
index 9f01ee1..09cd2ce 100644
--- a/vertica_python/tests/test_unicode.py
+++ b/vertica_python/tests/test_unicode.py
@@ -63,3 +63,29 @@ class UnicodeTestCase(VerticaPythonTestCase):
res = cur.fetchone()
self.assertResultEqual(value, res[0])
+
+ # unit test for issue #160
+ def test_null_named_parameter_binding(self):
+ key = u'test'
+ value = None
+ query = u"SELECT :{0}".format(key)
+
+ with self._connect() as conn:
+ cur = conn.cursor()
+ cur.execute(query, {key: value})
+ res = cur.fetchone()
+
+ self.assertResultEqual(value, res[0])
+
+ # unit test for issue #160
+ def test_null_list_parameter(self):
+ values = [u'\u00f1', 'foo', None]
+ query = u"SELECT {0}".format(", ".join(["%s"] * len(values)))
+
+ with self._connect() as conn:
+ cur = conn.cursor()
+ cur.execute(query, tuple(values))
+ results = cur.fetchone()
+
+ for val, res in zip(values, results):
+ self.assertResultEqual(val, res)
diff --git a/vertica_python/vertica/cursor.py b/vertica_python/vertica/cursor.py
index e9ae88f..d2b9be3 100644
--- a/vertica_python/vertica/cursor.py
+++ b/vertica_python/vertica/cursor.py
@@ -37,14 +37,19 @@ if six.PY2:
elif six.PY3:
file_type = (IOBase,)
+NULL = "NULL"
+
+RE_NAME_BASE = u"[a-zA-Z_][\\w\\d\\$_]*"
+RE_NAME = u'(("{0}")|({0}))'.format(RE_NAME_BASE)
+RE_BASIC_INSERT_STAT = (
+ u"INSERT\\s+INTO\\s+(?P<target>({0}\\.)?{0})"
+ u"\\s*\\(\\s*(?P<variables>{0}(\\s*,\\s*{0})*)\\s*\\)"
+ u"\\s+VALUES\\s*\\(\\s*(?P<values>.*)\\s*\\)").format(RE_NAME)
+
class Cursor(object):
# NOTE: this is used in executemany and is here for pandas compatibility
- _insert_statement = re.compile(
- u"INSERT\\s+INTO"
- "\\s+((?P<schema>{id})\\.)?(?P<table>{id})"
- "\\s*\\(\\s*(?P<variables>({id}(\\s*,\\s*{id})*)?\\s*)\\)"
- "\\s+VALUES\\s*\\(\\s*(?P<values>.*)\\)".format(id=u"[a-zA-Z_][\\w\\d\\$_]*"), re.U | re.I)
+ _insert_statement = re.compile(RE_BASIC_INSERT_STAT, re.U | re.I)
def __init__(self, connection, cursor_type=None, unicode_error=None):
self.connection = connection
@@ -98,7 +103,7 @@ class Cursor(object):
if parameters:
# TODO: quote = True for backward compatibility. see if should be False.
- operation = self.format_operation_with_parameters(operation, parameters, quote=True)
+ operation = self.format_operation_with_parameters(operation, parameters)
self.rowcount = -1
@@ -130,23 +135,20 @@ class Cursor(object):
m = self._insert_statement.match(operation)
if m:
- schema = as_text(m.group('schema'))
- table = as_text(m.group('table'))
- variables = as_text(m.group('variables'))
- values = as_text(m.group('values'))
- if schema is not None:
- table = "%s.%s" % (schema, table)
+ target = as_text(m.group('target'))
- variables = ",".join([variable.strip() for variable in variables.split(",")])
+ variables = as_text(m.group('variables'))
+ variables = ",".join([variable.strip().strip('"') for variable in variables.split(",")])
- values = ",".join([value.strip() for value in values.split(",")])
- seq_of_values = [self.format_operation_with_parameters(values, parameters)
+ values = as_text(m.group('values'))
+ values = ",".join([value.strip().strip('"') for value in values.split(",")])
+ seq_of_values = [self.format_operation_with_parameters(values, parameters, is_csv=True)
for parameters in seq_of_parameters]
data = "\n".join(seq_of_values)
copy_statement = (
- "COPY {table} ({variables}) FROM STDIN DELIMITER ',' ENCLOSED BY '\"' "
- "ENFORCELENGTH ABORT ON ERROR").format(table=table, variables=variables)
+ u"COPY {0} ({1}) FROM STDIN DELIMITER ',' ENCLOSED BY '\"' "
+ u"ENFORCELENGTH ABORT ON ERROR").format(target, variables)
self.copy(copy_statement, data)
@@ -261,7 +263,7 @@ class Cursor(object):
EXAMPLE:
>> with open("/tmp/file.csv", "rb") as fs:
- >> cursor.copy("COPY table(field1,field2) FROM STDIN DELIMITER ',' ENCLOSED BY '\"'",
+ >> cursor.copy("COPY table(field1,field2) FROM STDIN DELIMITER ',' ENCLOSED BY ''''",
>> fs, buffer_size=65536)
"""
@@ -327,7 +329,7 @@ class Cursor(object):
for idx, value in enumerate(row_data.values)]
# noinspection PyArgumentList
- def format_operation_with_parameters(self, operation, parameters, quote=True):
+ def format_operation_with_parameters(self, operation, parameters, is_csv=False):
operation = as_text(operation)
if isinstance(parameters, dict):
@@ -337,9 +339,9 @@ class Cursor(object):
key = as_text(key)
if isinstance(param, string_types):
- param = as_text(param)
- if quote:
- param = self.format_quote(param)
+ param = self.format_quote(as_text(param), is_csv)
+ elif param is None:
+ param = NULL
else:
param = str(param)
value = as_text(param)
@@ -353,9 +355,9 @@ class Cursor(object):
tlist = []
for param in parameters:
if isinstance(param, string_types):
- param = as_text(param)
- if quote:
- param = self.format_quote(param)
+ param = self.format_quote(as_text(param), is_csv)
+ elif param is None:
+ param = NULL
else:
param = str(param)
value = as_text(param)
@@ -368,6 +370,9 @@ class Cursor(object):
return operation
- def format_quote(self, param):
+ def format_quote(self, param, is_csv):
# TODO Make sure adapt() behaves properly
- return QuotedString(param.encode(UTF_8, self.unicode_error)).getquoted()
+ if is_csv:
+ return '"{0}"'.format(re.escape(param))
+ else:
+ return QuotedString(param.encode(UTF_8, self.unicode_error)).getquoted()
diff --git a/vertica_python/vertica/messages/message.py b/vertica_python/vertica/messages/message.py
index a72cdb9..5601c08 100644
--- a/vertica_python/vertica/messages/message.py
+++ b/vertica_python/vertica/messages/message.py
@@ -46,6 +46,7 @@ class BackendMessage(Message):
if klass is not None:
return klass(data)
else:
+ from .backend_messages import Unknown
return Unknown(type_, data)
@staticmethod
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-vertica.git
More information about the Python-modules-commits
mailing list