Skip to content

Commit

Permalink
OWSql: Inherit from OWBaseSql
Browse files Browse the repository at this point in the history
  • Loading branch information
VesnaT committed Oct 7, 2019
1 parent f67040a commit 85da948
Showing 1 changed file with 65 additions and 179 deletions.
244 changes: 65 additions & 179 deletions Orange/widgets/data/owsql.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
from collections import OrderedDict

from AnyQt.QtWidgets import (
QLineEdit, QComboBox, QTextEdit, QMessageBox, QSizePolicy, QApplication)
from AnyQt.QtWidgets import QComboBox, QTextEdit, QMessageBox, QApplication
from AnyQt.QtGui import QCursor
from AnyQt.QtCore import Qt, QTimer

from Orange.widgets import report
from Orange.data import Table
from Orange.data.sql.backend import Backend
from Orange.data.sql.backend.base import BackendError
from Orange.data.sql.table import SqlTable, LARGE_TABLE, AUTO_DL_LIMIT
from Orange.widgets import gui
from Orange.widgets.credentials import CredentialManager
from Orange.widgets.settings import Setting
from Orange.widgets.utils.itemmodels import PyListModel
from Orange.widgets.utils.owbasesql import OWBaseSql
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.widget import OWWidget, Output, Msg
from Orange.widgets.widget import Output, Msg

MAX_DL_LIMIT = 1000000

Expand All @@ -40,7 +36,7 @@ def data(self, index, role=Qt.DisplayRole):
return super().data(index, role)


class OWSql(OWWidget):
class OWSql(OWBaseSql):
name = "SQL Table"
id = "orange.widgets.data.sql"
description = "Load dataset from SQL."
Expand All @@ -54,15 +50,6 @@ class Outputs:

settings_version = 2

want_main_area = False
resizing_enabled = False

host = Setting(None)
port = Setting(None)
database = Setting(None)
schema = Setting(None)
username = ""
password = ""
table = Setting(None)
sql = Setting("")
guess_values = Setting(True)
Expand All @@ -71,83 +58,60 @@ class Outputs:
materialize = Setting(False)
materialize_table_name = Setting("")

class Information(OWWidget.Information):
class Information(OWBaseSql.Information):
data_sampled = Msg("Data description was generated from a sample.")

class Error(OWWidget.Error):
connection = Msg("{}")
no_backends = Msg("Please install a backend to use this widget")

class Warning(OWWidget.Warning):
class Warning(OWBaseSql.Warning):
missing_extension = Msg("Database is missing extensions: {}")

def __init__(self):
super().__init__()

self.backend = None
self.data_desc_table = None
self.database_desc = None
QTimer.singleShot(0, self.select_table)

vbox = gui.vBox(self.controlArea, "Server", addSpace=True)
box = gui.vBox(vbox)
def setup_gui(self):
super().setup_gui()
gui.checkBox(self.serverbox, self, "guess_values",
"Auto-discover categorical variables",
callback=self.open_table)
self.downloadcb = gui.checkBox(self.serverbox, self, "download",
"Download data to local memory",
callback=self.open_table)
gui.rubber(self.buttonsArea)
if self.can_connect:
self.connect()
index = self.tablecombo.findText(str(self.table))
if index != -1:
self.tablecombo.setCurrentIndex(index)

def add_main_layout(self):
self.backends = BackendModel(Backend.available_backends())
self.backendcombo = QComboBox(box)
self.backendcombo = QComboBox(self.serverbox)
if self.backends:
self.backendcombo.setModel(self.backends)
else:
self.Error.no_backends()
box.setEnabled(False)
box.layout().addWidget(self.backendcombo)

self.servertext = QLineEdit(box)
self.servertext.setPlaceholderText('Server')
self.servertext.setToolTip('Server')
self.servertext.editingFinished.connect(self._load_credentials)
if self.host:
self.servertext.setText(self.host if not self.port else
'{}:{}'.format(self.host, self.port))
box.layout().addWidget(self.servertext)

self.databasetext = QLineEdit(box)
self.databasetext.setPlaceholderText('Database[/Schema]')
self.databasetext.setToolTip('Database or optionally Database/Schema')
if self.database:
self.databasetext.setText(
self.database if not self.schema else
'{}/{}'.format(self.database, self.schema))
box.layout().addWidget(self.databasetext)
self.usernametext = QLineEdit(box)
self.usernametext.setPlaceholderText('Username')
self.usernametext.setToolTip('Username')

box.layout().addWidget(self.usernametext)
self.passwordtext = QLineEdit(box)
self.passwordtext.setPlaceholderText('Password')
self.passwordtext.setToolTip('Password')
self.passwordtext.setEchoMode(QLineEdit.Password)

box.layout().addWidget(self.passwordtext)

self._load_credentials()
self.tables = TableModel()
self.serverbox.setEnabled(False)
self.serverbox.layout().addWidget(self.backendcombo)

super().add_main_layout()

tables = gui.hBox(box)
self.tables = TableModel()
self.tablesbox = gui.hBox(self.serverbox)
self.tablecombo = QComboBox(
minimumContentsLength=35,
sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength
)
self.tablecombo.setModel(self.tables)
self.tablecombo.setToolTip('table')
tables.layout().addWidget(self.tablecombo)

self.connectbutton = gui.button(
tables, self, '↻', callback=self.connect)
self.connectbutton.setSizePolicy(
QSizePolicy.Fixed, QSizePolicy.Fixed)
tables.layout().addWidget(self.connectbutton)
self.tablesbox.layout().addWidget(self.tablecombo)
# set up the callback to select_table in case of selection change
self.tablecombo.activated[int].connect(self.select_table)

self.custom_sql = gui.vBox(box)
def add_connect_button(self):
super().add_connect_button()
self.tablesbox.layout().addWidget(self.connectbutton)
self.custom_sql = gui.vBox(self.serverbox)
self.custom_sql.setVisible(False)
self.sqltext = QTextEdit(self.custom_sql)
self.sqltext.setPlainText(self.sql)
Expand All @@ -158,104 +122,45 @@ def __init__(self):
cb.setToolTip('Save results of the query in a table')
le = gui.lineEdit(mt, self, 'materialize_table_name')
le.setToolTip('Save results of the query in a table')
self.serverbox.layout().addWidget(self.custom_sql)

self.executebtn = gui.button(
self.custom_sql, self, 'Execute', callback=self.open_table)

box.layout().addWidget(self.custom_sql)

gui.checkBox(box, self, "guess_values",
"Auto-discover categorical variables",
callback=self.open_table)

self.downloadcb = gui.checkBox(box, self, "download",
"Download data to local memory",
callback=self.open_table)

gui.rubber(self.buttonsArea)

self.connect()
index = self.tablecombo.findText(str(self.table))
if index != -1:
self.tablecombo.setCurrentIndex(index)
# set up the callback to select_table in case of selection change
self.tablecombo.activated[int].connect(self.select_table)

QTimer.singleShot(0, self.select_table)

def _load_credentials(self):
self._parse_host_port()
cm = self._credential_manager(self.host, self.port)
self.username = cm.username
self.password = cm.password

if self.username:
self.usernametext.setText(self.username)
if self.password:
self.passwordtext.setText(self.password)

def _save_credentials(self):
cm = self._credential_manager(self.host, self.port)
cm.username = self.username or ''
cm.password = self.password or ''

@staticmethod
def _credential_manager(host, port):
return CredentialManager("SQL Table: {}:{}".format(host, port))
def add_execute_button(self):
super().add_execute_button()
self.custom_sql.layout().addWidget(self.executebutton)

def highlight_error(self, text=""):
err = ['', 'QLineEdit {border: 2px solid red;}']
self.servertext.setStyleSheet(err['server' in text or 'host' in text])
self.usernametext.setStyleSheet(err['role' in text])
self.databasetext.setStyleSheet(err['database' in text])

def _parse_host_port(self):
hostport = self.servertext.text().split(':')
self.host = hostport[0]
self.port = hostport[1] if len(hostport) == 2 else None

def connect(self):
self._parse_host_port()
self.database, _, self.schema = self.databasetext.text().partition('/')
self.username = self.usernametext.text() or None
self.password = self.passwordtext.text() or None
def get_backend(self):
if self.backendcombo.currentIndex() < 0:
return None
return self.backends[self.backendcombo.currentIndex()]

def on_connection_success(self):
if getattr(self.backend, 'missing_extension', False):
self.Warning.missing_extension(
", ".join(self.backend.missing_extension))
self.download = True
self.downloadcb.setEnabled(False)
if not is_postgres(self.backend):
self.download = True
self.downloadcb.setEnabled(False)
super().on_connection_success()
self.refresh_tables()

def on_connection_error(self, err):
super().on_connection_error(err)
self.highlight_error(str(err).split("\n")[0])

def clear(self):
super().clear()
self.Warning.missing_extension.clear()
self.downloadcb.setEnabled(True)
try:
if self.backendcombo.currentIndex() < 0:
return
backend = self.backends[self.backendcombo.currentIndex()]
self.backend = backend(dict(
host=self.host,
port=self.port,
database=self.database,
user=self.username,
password=self.password
))
self.Error.connection.clear()
self.highlight_error()
if getattr(self.backend, 'missing_extension', False):
self.Warning.missing_extension(
", ".join(self.backend.missing_extension))
self.download = True
self.downloadcb.setEnabled(False)

if not is_postgres(self.backend):
self.download = True
self.downloadcb.setEnabled(False)

self._save_credentials()
self.database_desc = OrderedDict((
("Host", self.host), ("Port", self.port),
("Database", self.database), ("User name", self.username)
))
self.refresh_tables()
except BackendError as err:
error = str(err).split('\n')[0]
self.Error.connection(error)
self.highlight_error(error)
self.database_desc = self.data_desc_table = None
self.tablecombo.clear()
self.highlight_error()
self.tablecombo.clear()

def refresh_tables(self):
self.tables.clear()
Expand All @@ -282,16 +187,6 @@ def select_table(self):
return self.open_table()
return None

#self.Error.missing_extension(
# 's' if len(missing) > 1 else '',
# ', '.join(missing),
# shown=missing)

def open_table(self):
table = self.get_table()
self.data_desc_table = table
self.Outputs.data.send(table)

def get_table(self):
curIdx = self.tablecombo.currentIndex()
if curIdx <= 0:
Expand Down Expand Up @@ -414,15 +309,6 @@ def get_table(self):

return table

def send_report(self):
if not self.database_desc:
self.report_paragraph("No database connection.")
return
self.report_items("Database", self.database_desc)
if self.data_desc_table:
self.report_items("Data",
report.describe_data(self.data_desc_table))

@classmethod
def migrate_settings(cls, settings, version):
if version < 2:
Expand Down

0 comments on commit 85da948

Please sign in to comment.