From 546aa769d4915d8cbe4be284cfcd8a548960b5b7 Mon Sep 17 00:00:00 2001 From: Javier Sancho Date: Thu, 4 Oct 2018 12:26:57 +0200 Subject: [PATCH] Better features separation --- datasette_connectors/__init__.py | 87 -------------------------------- datasette_connectors/cli.py | 3 ++ datasette_connectors/monkey.py | 87 ++++++++++++++++++++++++++++++++ setup.py | 2 +- 4 files changed, 91 insertions(+), 88 deletions(-) create mode 100644 datasette_connectors/cli.py create mode 100644 datasette_connectors/monkey.py diff --git a/datasette_connectors/__init__.py b/datasette_connectors/__init__.py index 43f1101..e69de29 100644 --- a/datasette_connectors/__init__.py +++ b/datasette_connectors/__init__.py @@ -1,87 +0,0 @@ -import asyncio -import datasette -from datasette.app import connections -from datasette.cli import cli -from datasette.inspect import inspect_hash -from datasette.utils import Results -from pathlib import Path -import sqlite3 - - -# Monkey patching for original Datasette -def inspect(self): - " Inspect the database and return a dictionary of table metadata " - if self._inspect: - return self._inspect - - _inspect = {} - files = self.files - - for filename in files: - self.files = (filename,) - path = Path(filename) - name = path.stem - if name in _inspect: - raise Exception("Multiple files with the same stem %s" % name) - try: - _inspect[name] = self.original_inspect()[name] - except sqlite3.DatabaseError: - tables, views, dbtype = connectors.inspect(path) - _inspect[name] = { - "hash": inspect_hash(path), - "file": str(path), - "dbtype": dbtype, - "tables": tables, - "views": views, - } - - self.files = files - self._inspect = _inspect - return self._inspect - -datasette.app.Datasette.original_inspect = datasette.app.Datasette.inspect -datasette.app.Datasette.inspect = inspect - - -async def execute(self, db_name, sql, params=None, truncate=False, custom_time_limit=None, page_size=None): - """Executes sql against db_name in a thread""" - page_size = page_size or self.page_size - - def is_sqlite3_conn(): - conn = getattr(connections, db_name, None) - if not conn: - info = self.inspect()[db_name] - return info.get('dbtype', 'sqlite3') == 'sqlite3' - else: - return isinstance(conn, sqlite3.Connection) - - def sql_operation_in_thread(): - conn = getattr(connections, db_name, None) - if not conn: - info = self.inspect()[db_name] - conn = connectors.connect(info['file'], info['dbtype']) - setattr(connections, db_name, conn) - - rows, truncated, description = conn.execute( - sql, - params or {}, - truncate=truncate, - page_size=page_size, - max_returned_rows=self.max_returned_rows, - ) - return Results(rows, truncated, description) - - if is_sqlite3_conn(): - return await self.original_execute(db_name, sql, params=params, truncate=truncate, custom_time_limit=custom_time_limit, page_size=page_size) - else: - return await asyncio.get_event_loop().run_in_executor( - self.executor, sql_operation_in_thread - ) - -datasette.app.Datasette.original_execute = datasette.app.Datasette.execute -datasette.app.Datasette.execute = execute - - -# Read external database connectors -from . import connectors -connectors.load_connectors() diff --git a/datasette_connectors/cli.py b/datasette_connectors/cli.py new file mode 100644 index 0000000..2e8d2f5 --- /dev/null +++ b/datasette_connectors/cli.py @@ -0,0 +1,3 @@ +from .monkey import patch_datasette; patch_datasette() +from .connectors import load_connectors; load_connectors() +from datasette.cli import cli diff --git a/datasette_connectors/monkey.py b/datasette_connectors/monkey.py new file mode 100644 index 0000000..e18175f --- /dev/null +++ b/datasette_connectors/monkey.py @@ -0,0 +1,87 @@ +import asyncio +import datasette +from datasette.app import connections +from datasette.inspect import inspect_hash +from datasette.utils import Results +from pathlib import Path +import sqlite3 + +from . import connectors + + +def patch_datasette(): + """ + Monkey patching for original Datasette + """ + + def inspect(self): + " Inspect the database and return a dictionary of table metadata " + if self._inspect: + return self._inspect + + _inspect = {} + files = self.files + + for filename in files: + self.files = (filename,) + path = Path(filename) + name = path.stem + if name in _inspect: + raise Exception("Multiple files with the same stem %s" % name) + try: + _inspect[name] = self.original_inspect()[name] + except sqlite3.DatabaseError: + tables, views, dbtype = connectors.inspect(path) + _inspect[name] = { + "hash": inspect_hash(path), + "file": str(path), + "dbtype": dbtype, + "tables": tables, + "views": views, + } + + self.files = files + self._inspect = _inspect + return self._inspect + + datasette.app.Datasette.original_inspect = datasette.app.Datasette.inspect + datasette.app.Datasette.inspect = inspect + + + async def execute(self, db_name, sql, params=None, truncate=False, custom_time_limit=None, page_size=None): + """Executes sql against db_name in a thread""" + page_size = page_size or self.page_size + + def is_sqlite3_conn(): + conn = getattr(connections, db_name, None) + if not conn: + info = self.inspect()[db_name] + return info.get('dbtype', 'sqlite3') == 'sqlite3' + else: + return isinstance(conn, sqlite3.Connection) + + def sql_operation_in_thread(): + conn = getattr(connections, db_name, None) + if not conn: + info = self.inspect()[db_name] + conn = connectors.connect(info['file'], info['dbtype']) + setattr(connections, db_name, conn) + + rows, truncated, description = conn.execute( + sql, + params or {}, + truncate=truncate, + page_size=page_size, + max_returned_rows=self.max_returned_rows, + ) + return Results(rows, truncated, description) + + if is_sqlite3_conn(): + return await self.original_execute(db_name, sql, params=params, truncate=truncate, custom_time_limit=custom_time_limit, page_size=page_size) + else: + return await asyncio.get_event_loop().run_in_executor( + self.executor, sql_operation_in_thread + ) + + datasette.app.Datasette.original_execute = datasette.app.Datasette.execute + datasette.app.Datasette.execute = execute diff --git a/setup.py b/setup.py index 764fbf9..4b7d0f4 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,6 @@ setup( install_requires=['datasette==0.25'], entry_points=''' [console_scripts] - datasette=datasette_connectors:cli + datasette=datasette_connectors.cli:cli ''' ) -- 2.39.2