# encoding: utf-8
"""
.. codeauthor:: Tsuyoshi Hombashi <gogogo.vm@gmail.com>
"""
from __future__ import absolute_import
import logging
import os
import sqlite3
import sys
import dataproperty
import pathvalidate
import six
from six.moves import range
import simplesqlite
from .sqlquery import SqlQuery
from .converter import RecordConvertor
[docs]class SimpleSQLite(object):
"""
Wrapper class of |sqlite3| module.
:param str database_path: File path of the database to be connected.
:param str mode: Open mode.
:param bool profile:
Recording SQL query execution time profile, if the value is |True|.
.. seealso::
:py:meth:`.connect`
:py:meth:`.get_profile`
"""
@property
def database_path(self):
"""
:return: File path of the connected database.
:rtype: str
:Examples:
>>> from simplesqlite import SimpleSQLite
>>> con = SimpleSQLite("sample.sqlite", "w")
>>> con.database_path
'/tmp/sample.sqlite'
>>> con.close()
>>> print(con.database_path)
None
"""
return self.__database_path
@property
def connection(self):
"""
:return: |Connection| instance of the connected database.
:rtype: sqlite3.Connection
"""
return self.__connection
@property
def mode(self):
"""
:return: Connection mode: ``"r"``/``"w"``/``"a"``.
:rtype: str
.. seealso:: :py:meth:`.connect`
"""
return self.__mode
def __init__(
self, database_path, mode="a",
is_create_table_config=True, profile=False):
self.__initialize_connection()
self.__is_profile = profile
self.__is_create_table_config = is_create_table_config
self.connect(database_path, mode)
def __del__(self):
self.close()
def __exit__(self, exc_type, exc_value, traceback):
self.close()
[docs] def is_connected(self):
"""
:return: |True| if the connection to a database is valid.
:rtype: bool
:Examples:
>>> from simplesqlite import SimpleSQLite
>>> con = SimpleSQLite("sample.sqlite", "w")
>>> con.is_connected()
True
>>> con.close()
>>> con.is_connected()
False
"""
try:
self.check_connection()
except simplesqlite.NullDatabaseConnectionError:
return False
return True
[docs] def check_connection(self):
"""
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, NullDatabaseConnectionError
import six
con = SimpleSQLite("sample.sqlite", "w")
six.print_("---- connected to a database ----")
con.check_connection()
six.print_("---- disconnected from a database ----")
con.close()
try:
con.check_connection()
except NullDatabaseConnectionError as e:
six.print_(e)
.. parsed-literal::
---- connected to a database ----
---- disconnected from a database ----
null database connection
"""
if self.connection is None:
raise simplesqlite.NullDatabaseConnectionError(
"null database connection")
if dataproperty.is_empty_string(self.database_path):
raise simplesqlite.NullDatabaseConnectionError(
"null database file path")
[docs] def connect(self, database_path, mode="a"):
"""
:param str database_path:
Path to the SQLite database file to be connected.
:param str mode:
``"r"``: Open for read only.
``"w"``: Open for read/write.
Delete existing tables when connecting.
``"a"``: Open for read/write. Append to the existing tables.
:raises ValueError:
If ``database_path`` is invalid or |attr_mode| is invalid.
:raises sqlite3.OperationalError: If unable to open the database file.
"""
self.close()
if mode == "r":
self.__verify_sqlite_db_file(database_path)
elif mode in ["w", "a"]:
self.__validate_db_path(database_path)
else:
raise ValueError("unknown connection mode: " + mode)
if database_path == simplesqlite.MEMORY_DB_NAME:
self.__database_path = database_path
else:
self.__database_path = os.path.realpath(database_path)
self.__connection = sqlite3.connect(database_path)
self.__mode = mode
if mode != "w":
return
for table in self.get_table_name_list():
self.drop_table(table)
[docs] def execute_query(self, query, caller=None):
"""
Execute arbitrary SQLite query.
:param str query: Query to be executed.
:param tuple caller:
Caller information.
Expects the return value of :py:meth:`logging.Logger.findCaller`.
:return: Result of the query execution.
:rtype: sqlite3.Cursor
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises sqlite3.OperationalError: |raises_operational_error|
.. warning::
This method can execute an arbitrary query.
i.e. No access permissions check by |attr_mode|.
"""
import time
self.check_connection()
if dataproperty.is_empty_string(query):
return None
if self.__is_profile:
exec_start_time = time.time()
try:
result = self.connection.execute(query)
except sqlite3.OperationalError:
_, e, _ = sys.exc_info() # for python 2.5 compatibility
if caller is None:
caller = logging.getLogger().findCaller()
file_path, line_no, func_name = caller[:3]
message_list = [
"failed to execute query at %s(%d) %s" % (
file_path, line_no, func_name),
" - query: %s" % (query),
" - msg: %s" % (e),
" - db: %s" % (self.database_path),
]
raise sqlite3.OperationalError(os.linesep.join(message_list))
if self.__is_profile:
self.__dict_query_count[query] = (
self.__dict_query_count.get(query, 0) + 1)
elapse_time = time.time() - exec_start_time
self.__dict_query_totalexectime[query] = (
self.__dict_query_totalexectime.get(query, 0) + elapse_time)
return result
[docs] def select(self, select, table_name, where=None, extra=None):
"""
Execute SELECT query.
:param str select: Attribute for the SELECT query.
:param str table_name: Table name of executing the query.
:return: Result of the query execution.
:rtype: sqlite3.Cursor
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises sqlite3.OperationalError: |raises_operational_error|
.. seealso::
:py:meth:`.sqlquery.SqlQuery.make_select`
"""
self.verify_table_existence(table_name)
query = SqlQuery.make_select(select, table_name, where, extra)
return self.execute_query(query, logging.getLogger().findCaller())
[docs] def insert(self, table_name, insert_record):
"""
Execute INSERT query.
:param str table_name: Table name of executing the query.
:param insert_record: Record to be inserted.
:type insert_record: |dict|/|namedtuple|/|list|/|tuple|
:raises IOError: |raises_write_permission|
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises sqlite3.OperationalError: |raises_operational_error|
.. seealso:: :py:meth:`.sqlquery.SqlQuery.make_insert`
"""
self.validate_access_permission(["w", "a"])
self.verify_table_existence(table_name)
query = SqlQuery.make_insert(table_name, RecordConvertor.to_record(
self.get_attribute_name_list(table_name), insert_record))
self.execute_query(query, logging.getLogger().findCaller())
[docs] def insert_many(self, table_name, insert_record_list):
"""
Execute INSERT query for multiple records.
:param str table: Table name of executing the query.
:param insert_record: Records to be inserted.
:type insert_record: |dict|/|namedtuple|/|list|/|tuple|
:raises IOError: |raises_write_permission|
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises sqlite3.OperationalError: |raises_operational_error|
.. seealso:: :py:meth:`.sqlquery.SqlQuery.make_insert`
"""
self.validate_access_permission(["w", "a"])
self.verify_table_existence(table_name)
if dataproperty.is_empty_list_or_tuple(insert_record_list):
return
record_list = RecordConvertor.to_record_list(
self.get_attribute_name_list(table_name), insert_record_list)
query = SqlQuery.make_insert(
table_name, record_list[0], is_insert_many=True)
try:
self.connection.executemany(query, record_list)
except sqlite3.OperationalError:
_, e, _ = sys.exc_info() # for python 2.5 compatibility
caller = logging.getLogger().findCaller()
file_path, line_no, func_name = caller[:3]
raise sqlite3.OperationalError(
"%s(%d) %s: failed to execute query:\n" % (
file_path, line_no, func_name) +
" query=%s\n" % (query) +
" msg='%s'\n" % (str(e)) +
" db=%s\n" % (self.database_path) +
" records=%s\n" % (record_list[:2])
)
[docs] def update(self, table_name, set_query, where=None):
"""
Execute UPDATE query.
:param str table_name: Table name of executing the query.
:param str set_query:
:raises IOError: |raises_write_permission|
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises sqlite3.OperationalError: |raises_operational_error|
.. seealso::
:py:meth:`.sqlquery.SqlQuery.make_update`
"""
self.validate_access_permission(["w", "a"])
self.verify_table_existence(table_name)
query = SqlQuery.make_update(table_name, set_query, where)
return self.execute_query(query, logging.getLogger().findCaller())
[docs] def get_total_changes(self):
"""
.. seealso::
:py:attr:`sqlite3.Connection.total_changes`
"""
self.check_connection()
return self.connection.total_changes
[docs] def get_value(self, select, table_name, where=None, extra=None):
"""
Get a value from the table.
:param str select: Attribute for SELECT query
:param str table_name: Table name of executing the query.
:return: Result of execution of the query.
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises sqlite3.OperationalError: |raises_operational_error|
.. seealso::
:py:meth:`.sqlquery.SqlQuery.make_select`
"""
self.verify_table_existence(table_name)
query = SqlQuery.make_select(select, table_name, where, extra)
result = self.execute_query(query, logging.getLogger().findCaller())
if result is None:
return None
fetch = result.fetchone()
if fetch is None:
return None
return fetch[0]
[docs] def get_table_name_list(self):
"""
:return: List of table names in the database.
:rtype: list
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises sqlite3.OperationalError: |raises_operational_error|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name="hoge",
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
six.print_(con.get_table_name_list())
.. parsed-literal::
[u'hoge']
"""
self.check_connection()
query = "SELECT name FROM sqlite_master WHERE TYPE='table'"
result = self.execute_query(query, logging.getLogger().findCaller())
if result is None:
return []
return self.__get_list_from_fetch(result.fetchall())
[docs] def get_attribute_name_list(self, table_name):
"""
:return: List of attribute names in the table.
:rtype: list
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises sqlite3.OperationalError: |raises_operational_error|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, TableNotFoundError
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name=table_name,
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
six.print_(con.get_attribute_name_list(table_name))
try:
six.print_(con.get_attribute_name_list("not_existing"))
except TableNotFoundError as e:
six.print_(e)
.. parsed-literal::
['attr_a', 'attr_b']
'not_existing' table not found in /tmp/sample.sqlite
"""
self.verify_table_existence(table_name)
query = "SELECT * FROM '%s'" % (table_name)
result = self.execute_query(query, logging.getLogger().findCaller())
return self.__get_list_from_fetch(result.description)
[docs] def get_attribute_type_list(self, table_name):
"""
:return: List of attribute names in the table.
:rtype: list
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises sqlite3.OperationalError: |raises_operational_error|
"""
self.verify_table_existence(table_name)
attribute_name_list = self.get_attribute_name_list(table_name)
query = "SELECT DISTINCT %s FROM '%s'" % (
",".join([
"TYPEOF(%s)" % (SqlQuery.to_attr_str(attribute))
for attribute in attribute_name_list]),
table_name)
result = self.execute_query(query, logging.getLogger().findCaller())
return result.fetchone()
[docs] def get_profile(self, profile_count=50):
"""
Get profile of query execution time.
:param int profile_count:
Number of profiles to retrieve,
counted from the top query in descending order by
the cumulative execution time.
:return: Profile information for each query.
:rtype: list of |namedtuple|
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises sqlite3.OperationalError: |raises_operational_error|
"""
from collections import namedtuple
profile_table_name = "sql_profile"
value_matrix = [
[query, execute_time, self.__dict_query_count.get(query, 0)]
for query, execute_time
in six.iteritems(self.__dict_query_totalexectime)
]
attribute_name_list = ("query", "cumulative_time", "count")
con_tmp = simplesqlite.connect_sqlite_db_mem()
try:
con_tmp.create_table_with_data(
profile_table_name,
attribute_name_list,
data_matrix=value_matrix)
except ValueError:
return []
try:
result = con_tmp.select(
select="%s,SUM(%s),SUM(%s)" % attribute_name_list,
table_name=profile_table_name,
extra="GROUP BY %s ORDER BY %s DESC LIMIT %d" % (
"query", "cumulative_time", profile_count))
except sqlite3.OperationalError:
return []
if result is None:
return []
SqliteProfile = namedtuple(
"SqliteProfile", " ".join(attribute_name_list))
return [SqliteProfile(*profile) for profile in result.fetchall()]
[docs] def get_sqlite_master(self):
"""
Get sqlite_master table information as a list of dictionaries.
:return: sqlite_master table information.
:rtype: list
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:Examples:
.. code:: python
import json
from simplesqlite import SimpleSQLite
con = SimpleSQLite("sample.sqlite", "w")
data_matrix = [
[1, 1.1, "aaa", 1, 1],
[2, 2.2, "bbb", 2.2, 2.2],
[3, 3.3, "ccc", 3, "ccc"],
]
con.create_table_with_data(
table_name="sample_table",
attribute_name_list=["a", "b", "c", "d", "e"],
data_matrix=data_matrix,
index_attribute_list=["a"])
print(json.dumps(con.get_sqlite_master(), indent=4))
.. parsed-literal::
[
{
"tbl_name": "sample_table",
"sql": "CREATE TABLE 'sample_table' ('a' INTEGER, 'b' REAL, 'c' TEXT, 'd' REAL, 'e' TEXT)",
"type": "table",
"name": "sample_table",
"rootpage": 2
},
{
"tbl_name": "sample_table",
"sql": "CREATE INDEX sample_table_a_index ON sample_table('a')",
"type": "index",
"name": "sample_table_a_index",
"rootpage": 3
}
]
"""
self.check_connection()
old_row_factory = self.connection.row_factory
self.connection.row_factory = sqlite3.Row
sqlite_master_list = []
result = self.execute_query("select * from sqlite_master")
for item in result.fetchall():
sqlite_master_list.append(
dict([[key, item[key]] for key in item.keys()]))
self.connection.row_factory = old_row_factory
return sqlite_master_list
[docs] def has_table(self, table_name):
"""
:param str table_name: Table name to be tested.
:return: |True| if the database has the table.
:rtype: bool
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite
import six
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name="hoge",
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
six.print_(con.has_table("hoge"))
six.print_(con.has_table("not_existing"))
.. parsed-literal::
True
False
"""
try:
simplesqlite.validate_table_name(table_name)
except ValueError:
return False
return table_name in self.get_table_name_list()
[docs] def has_attribute(self, table_name, attribute_name):
"""
:param str table_name: Table name that exists attribute.
:param str attribute_name: Attribute name to be tested.
:return: |True| if the table has the attribute.
:rtype: bool
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, TableNotFoundError
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name=table_name,
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
six.print_(con.has_attribute(table_name, "attr_a"))
six.print_(con.has_attribute(table_name, "not_existing"))
try:
six.print_(con.has_attribute("not_existing", "attr_a"))
except TableNotFoundError as e:
six.print_(e)
.. parsed-literal::
True
False
'not_existing' table not found in /tmp/sample.sqlite
"""
self.verify_table_existence(table_name)
if dataproperty.is_empty_string(attribute_name):
return False
return attribute_name in self.get_attribute_name_list(table_name)
[docs] def has_attribute_list(self, table_name, attribute_name_list):
"""
:param str table_name: Table name that exists attribute.
:param str attribute_name_list: Attribute names to be tested.
:return: |True| if the table has all of the attribute.
:rtype: bool
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, TableNotFoundError
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name=table_name,
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
six.print_(con.has_attribute_list(table_name, ["attr_a"]))
six.print_(con.has_attribute_list(
table_name, ["attr_a", "attr_b"]))
six.print_(con.has_attribute_list(
table_name, ["attr_a", "attr_b", "not_existing"]))
try:
six.print_(con.has_attribute("not_existing", ["attr_a"]))
except TableNotFoundError as e:
six.print_(e)
.. parsed-literal::
True
True
False
'not_existing' table not found in /tmp/sample.sqlite
"""
if dataproperty.is_empty_list_or_tuple(attribute_name_list):
return False
not_exist_field_list = [
attribute_name
for attribute_name in attribute_name_list
if not self.has_attribute(table_name, attribute_name)
]
if len(not_exist_field_list) > 0:
return False
return True
[docs] def verify_table_existence(self, table_name):
"""
:param str table_name: Table name to be tested.
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:raises ValueError: |raises_validate_table_name|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, TableNotFoundError
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name=table_name,
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
con.verify_table_existence(table_name)
try:
con.verify_table_existence("not_existing")
except TableNotFoundError as e:
six.print_(e)
.. parsed-literal::
'not_existing' table not found in /tmp/sample.sqlite
"""
simplesqlite.validate_table_name(table_name)
if self.has_table(table_name):
return
raise simplesqlite.TableNotFoundError(
"'%s' table not found in %s" % (table_name, self.database_path))
[docs] def verify_attribute_existence(self, table_name, attribute_name):
"""
:param str table_name: Table name that exists attribute.
:param str attribute_name: Attribute name to be tested.
:raises simplesqlite.AttributeNotFoundError:
If attribute not found in the table
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
:Examples:
.. code:: python
from simplesqlite import SimpleSQLite, TableNotFoundError, AttributeNotFoundError
import six
table_name = "sample_table"
con = SimpleSQLite("sample.sqlite", "w")
con.create_table_with_data(
table_name=table_name,
attribute_name_list=["attr_a", "attr_b"],
data_matrix=[[1, "a"], [2, "b"]])
con.verify_attribute_existence(table_name, "attr_a")
try:
con.verify_attribute_existence(table_name, "not_existing")
except AttributeNotFoundError as e:
six.print_(e)
try:
con.verify_attribute_existence("not_existing", "attr_a")
except TableNotFoundError as e:
six.print_(e)
.. parsed-literal::
'not_existing' attribute not found in 'sample_table' table
'not_existing' table not found in /tmp/sample.sqlite
"""
self.verify_table_existence(table_name)
if self.has_attribute(table_name, attribute_name):
return
raise simplesqlite.AttributeNotFoundError(
"'%s' attribute not found in '%s' table" % (
attribute_name, table_name))
[docs] def drop_table(self, table_name):
"""
:param str table_name: Table name to drop.
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises IOError: |raises_write_permission|
"""
self.validate_access_permission(["w", "a"])
if self.has_table(table_name):
query = "DROP TABLE IF EXISTS '%s'" % (table_name)
self.execute_query(query, logging.getLogger().findCaller())
self.commit()
[docs] def create_table(self, table_name, attribute_description_list):
"""
:param str table_name: Table name to create.
:param list attribute_description_list: List of table description.
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises IOError: |raises_write_permission|
"""
self.validate_access_permission(["w", "a"])
table_name = table_name.strip()
if self.has_table(table_name):
return True
query = "CREATE TABLE IF NOT EXISTS '%s' (%s)" % (
table_name, ", ".join(attribute_description_list))
if self.execute_query(query, logging.getLogger().findCaller()) is None:
return False
return True
[docs] def create_index(self, table_name, attribute_name):
"""
:param str table_name:
Table name that contains the attribute to be indexed.
:param str attribute_name: Attribute name to create index.
:raises IOError: |raises_write_permission|
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
:raises simplesqlite.TableNotFoundError:
|raises_verify_table_existence|
"""
self.verify_table_existence(table_name)
self.validate_access_permission(["w", "a"])
index_name = "%s_%s_index" % (
SqlQuery.sanitize(table_name), SqlQuery.sanitize(attribute_name))
query = "CREATE INDEX IF NOT EXISTS %s ON %s('%s')" % (
index_name, SqlQuery.to_table_str(table_name), attribute_name)
self.execute_query(query, logging.getLogger().findCaller())
[docs] def create_index_list(self, table_name, attribute_name_list):
"""
:param str table_name: Table name that exists attribute.
:param list attribute_name_list:
List of attribute names to create indices.
.. seealso:: :py:meth:`.create_index`
"""
self.validate_access_permission(["w", "a"])
if dataproperty.is_empty_list_or_tuple(attribute_name_list):
return
for attribute in attribute_name_list:
self.create_index(table_name, attribute)
[docs] def create_table_with_data(
self, table_name, attribute_name_list, data_matrix,
index_attribute_list=()):
"""
Create a table if not exists. And insert data into the created table.
:param str table_name: Table name to create.
:param list attribute_name_list: List of attribute names of the table.
:param data_matrix: Data to be inserted into the table.
:type data_matrix: List of |dict|/|namedtuple|/|list|/|tuple|
:param tuple index_attribute_list:
List of attribute names of create indices.
:raises ValueError: If the ``data_matrix`` is empty.
.. seealso::
:py:meth:`.create_table`
:py:meth:`.insert_many`
:py:meth:`.create_index_list`
"""
simplesqlite.validate_table_name(table_name)
self.validate_access_permission(["w", "a"])
if dataproperty.is_empty_list_or_tuple(data_matrix):
raise ValueError("input data is null: '%s (%s)'" % (
table_name, ", ".join(attribute_name_list)))
data_matrix = RecordConvertor.to_record_list(
attribute_name_list, data_matrix)
self.__verify_value_matrix(attribute_name_list, data_matrix)
strip_index_attribute_list = list(
set(attribute_name_list).intersection(set(index_attribute_list)))
attr_description_list = []
for col, value_type in sorted(
six.iteritems(self.__get_column_valuetype(data_matrix))):
attr_name = attribute_name_list[col]
attr_description_list.append(
"'%s' %s" % (attr_name, value_type))
self.create_table(table_name, attr_description_list)
self.insert_many(table_name, data_matrix)
self.create_index_list(table_name, strip_index_attribute_list)
self.commit()
[docs] def create_table_from_tabledata(self, tabledata):
"""
Create a table from :py:class:`.loader.data.TableData`.
:param TableData tabledata: Table data to create.
.. seealso::
:py:meth:`.create_table_with_data`
"""
self.create_table_with_data(
table_name=tabledata.table_name,
attribute_name_list=tabledata.header_list,
data_matrix=tabledata.record_list)
[docs] def create_table_from_csv(
self, csv_source, table_name="",
attribute_name_list=(),
delimiter=",", quotechar='"', encoding="utf-8"):
"""
Create a table from a CSV file/text.
:param str csv_source: Path to the CSV file or CSV text.
:param str table_name:
Table name to create.
Use csv file basename as the table name if the value is empty.
:param list attribute_name_list:
Attribute names of the table.
Use the first line of the csv file as attribute list
if attribute_name_list is empty.
:param str delimiter:
A one-character string used to separate fields.
:param str quotechar:
A one-character string used to quote fields
containing special characters, such as the delimiter or quotechar,
or which contain new-line characters.
:param str encoding: csv file encoding.
:raises ValueError: If the csv data is invalid.
.. seealso::
:py:meth:`.create_table_with_data`
:py:func:`csv.reader`
:py:meth:`.loader.CsvTableFileLoader.load`
:py:meth:`.loader.CsvTableTextLoader.load`
"""
from .loader import CsvTableFileLoader
from .loader import CsvTableTextLoader
loader = CsvTableFileLoader(csv_source)
if dataproperty.is_not_empty_string(table_name):
loader.table_name = table_name
loader.header_list = attribute_name_list
loader.delimiter = delimiter
loader.quotechar = quotechar
loader.encoding = encoding
try:
for tabledata in loader.load():
self.create_table_from_tabledata(tabledata)
return
except IOError:
pass
loader = CsvTableTextLoader(csv_source)
if dataproperty.is_not_empty_string(table_name):
loader.table_name = table_name
loader.header_list = attribute_name_list
loader.delimiter = delimiter
loader.quotechar = quotechar
loader.encoding = encoding
for tabledata in loader.load():
self.create_table_from_tabledata(tabledata)
[docs] def create_table_from_json(self, json_source, table_name=""):
"""
Create a table from a JSON file/text.
:param str json_source: Path to the JSON file or JSON text.
:param str table_name: Table name to create.
.. seealso::
:py:meth:`.loader.JsonTableFileLoader.load`
:py:meth:`.loader.JsonTableTextLoader.load`
"""
from .loader import JsonTableFileLoader
from .loader import JsonTableTextLoader
loader = JsonTableFileLoader(json_source)
if dataproperty.is_not_empty_string(table_name):
loader.table_name = table_name
try:
for tabledata in loader.load():
self.create_table_from_tabledata(tabledata)
return
except IOError:
pass
loader = JsonTableTextLoader(json_source)
if dataproperty.is_not_empty_string(table_name):
loader.table_name = table_name
for tabledata in loader.load():
self.create_table_from_tabledata(tabledata)
[docs] def rollback(self):
"""
.. seealso:: :py:meth:`sqlite3.Connection.rollback`
"""
try:
self.check_connection()
except simplesqlite.NullDatabaseConnectionError:
return
self.connection.rollback()
[docs] def commit(self):
"""
.. seealso:: :py:meth:`sqlite3.Connection.commit`
"""
try:
self.check_connection()
except simplesqlite.NullDatabaseConnectionError:
return
self.connection.commit()
[docs] def close(self):
"""
Commit and close the connection.
.. seealso:: :py:meth:`sqlite3.Connection.close`
"""
try:
self.check_connection()
except simplesqlite.NullDatabaseConnectionError:
return
self.commit()
self.connection.close()
self.__initialize_connection()
@staticmethod
def __validate_db_path(database_path):
if dataproperty.is_empty_string(database_path):
raise ValueError("null path")
if database_path == simplesqlite.MEMORY_DB_NAME:
return
pathvalidate.validate_filename(os.path.basename(database_path))
def __verify_sqlite_db_file(self, database_path):
"""
:raises sqlite3.OperationalError: If unable to open database file.
"""
self.__validate_db_path(database_path)
if not os.path.isfile(os.path.realpath(database_path)):
raise IOError("file not found: " + database_path)
connection = sqlite3.connect(database_path)
connection.close()
@staticmethod
def __verify_value_matrix(field_list, value_matrix):
"""
:param list/tuple field_list:
:param list/tuple value_matrix: the list to test.
:raises ValueError:
"""
miss_match_idx_list = []
for list_idx in range(len(value_matrix)):
if len(field_list) == len(value_matrix[list_idx]):
continue
miss_match_idx_list.append(list_idx)
if len(miss_match_idx_list) == 0:
return
sample_miss_match_list = value_matrix[miss_match_idx_list[0]]
raise ValueError(
"miss match header length and value length:" +
" header: %d %s\n" % (len(field_list), str(field_list)) +
" # of miss match line: %d ouf of %d\n" % (
len(miss_match_idx_list), len(value_matrix)) +
" e.g. value at line=%d, len=%d: %s\n" % (
miss_match_idx_list[0],
len(sample_miss_match_list), str(sample_miss_match_list))
)
@staticmethod
def __get_list_from_fetch(result):
"""
:params tuple result: Return value from a Cursor.fetchall()
:rtype: list
"""
return [record[0] for record in result]
def __initialize_connection(self):
self.__database_path = None
self.__connection = None
self.__cursur = None
self.__mode = None
self.__dict_query_count = {}
self.__dict_query_totalexectime = {}
[docs] def validate_access_permission(self, valid_permission_list):
"""
:param valid_permission_list:
List of permissions that access is allowed.
:type valid_permission_list: |list|/|tuple|
:raises ValueError: If the |attr_mode| is invalid.
:raises IOError:
If the |attr_mode| not in the ``valid_permission_list``.
:raises simplesqlite.NullDatabaseConnectionError:
|raises_check_connection|
"""
self.check_connection()
if dataproperty.is_empty_string(self.mode):
raise ValueError("mode is not set")
if self.mode not in valid_permission_list:
raise IOError(
"invalid access: expected-mode=%s, current-mode=%s" % (
str(valid_permission_list), self.mode))
@staticmethod
def __get_column_valuetype(data_matrix):
"""
Get value type for each column.
:param list/tuple data_matrix:
:return: { column_number : value_type }
:rtype: dictionary
"""
typename_table = {
dataproperty.Typecode.INT: "INTEGER",
dataproperty.Typecode.FLOAT: "REAL",
dataproperty.Typecode.STRING: "TEXT",
}
prop_extractor = dataproperty.PropertyExtractor()
prop_extractor.data_matrix = data_matrix
col_prop_list = prop_extractor.extract_column_property_list()
return dict([
[col, typename_table[col_prop.typecode]]
for col, col_prop in enumerate(col_prop_list)
])