From 590e844057fcc7d221f2f9c01a11a86697250103 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 22 Jun 2025 19:58:40 +0200 Subject: [PATCH] Test der Datenbank-Verbindung --- pyproject.toml | 3 +- src/ui/AppSettings.py | 106 +++++++++++++++++++++++++++++++ src/ui/PostgreSqlConfigDialog.py | 20 ++++-- uv.lock | 46 ++++++++++++-- 4 files changed, 160 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3b66982..1568762 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,9 +8,8 @@ dependencies = [ "pyqtdarktheme>=2.1.0", "pydantic-settings>=2.9.1", "pyside6>=6.9.1", - "polars>=1.31.0", + "polars[connectorx,pyarrow]>=1.31.0", "pydantic-yaml>=1.5.1", - "connectorx>=0.4.3", ] [tool.ruff] diff --git a/src/ui/AppSettings.py b/src/ui/AppSettings.py index e4cc8bc..b4d49f2 100644 --- a/src/ui/AppSettings.py +++ b/src/ui/AppSettings.py @@ -37,6 +37,7 @@ class AppSettingsDlg(QDialog): self.temp_apache_fops = self.settings.apache_fops.copy() self.temp_xsl_dirs = self.settings.xsl_dirs.copy() self.temp_pdf_projects = self.settings.pdf_projects.copy() + self.temp_postgresql_dbs = self.settings.postgresql_dbs.copy() # Signale verbinden self._connect_signals() @@ -77,6 +78,11 @@ class AppSettingsDlg(QDialog): self.ui.addProject.clicked.connect(self._add_pdf_project) self.ui.tablePdfProjects.itemSelectionChanged.connect(self._update_pdf_project_buttons) + # PostgreSQL Tab + self.ui.addPostgreSql.clicked.connect(self._add_postgresql_db) + self.ui.removePostgreSql.clicked.connect(self._remove_postgresql_db) + self.ui.tablePostgreSqlDbs.itemSelectionChanged.connect(self._update_postgresql_db_buttons) + def _setup_tables(self): """Richtet die Tabellen-Header ein und macht sie unveränderbar.""" from PySide6.QtWidgets import QAbstractItemView @@ -111,6 +117,11 @@ class AppSettingsDlg(QDialog): self.ui.tablePdfProjects.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.ui.tablePdfProjects.doubleClicked.connect(self._edit_pdf_project) + # PostgreSQL Tabelle + self.ui.tablePostgreSqlDbs.setHorizontalHeaderLabels(["Name", "Host", "Port", "Datenbank", "Benutzer"]) + self.ui.tablePostgreSqlDbs.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) + self.ui.tablePostgreSqlDbs.doubleClicked.connect(self._edit_postgresql_db) + def _populate_tables(self): """Füllt alle Tabellen mit den aktuellen Einstellungen.""" self._populate_xsl_table() @@ -119,6 +130,7 @@ class AppSettingsDlg(QDialog): self._populate_apache_fop_table() self._populate_diff_pdf_table() self._populate_pdf_project_table() + self._populate_postgresql_db_table() def _populate_xsl_table(self): """Füllt die XSL-Ordner Tabelle.""" @@ -234,6 +246,31 @@ class AppSettingsDlg(QDialog): self.ui.tablePdfProjects.setItem(row, 6, diff_pdf_item) self.ui.tablePdfProjects.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) + def _populate_postgresql_db_table(self): + """Füllt die PostgreSQL-Datenbank Tabelle.""" + self.ui.tablePostgreSqlDbs.setRowCount(len(self.temp_postgresql_dbs)) + for row, postgresql_db in enumerate(self.temp_postgresql_dbs): + name_item = QTableWidgetItem(postgresql_db.name) + name_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.ui.tablePostgreSqlDbs.setItem(row, 0, name_item) + + host_item = QTableWidgetItem(postgresql_db.host) + host_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.ui.tablePostgreSqlDbs.setItem(row, 1, host_item) + + port_item = QTableWidgetItem(str(postgresql_db.port)) + port_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.ui.tablePostgreSqlDbs.setItem(row, 2, port_item) + + database_item = QTableWidgetItem(postgresql_db.database) + database_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.ui.tablePostgreSqlDbs.setItem(row, 3, database_item) + + username_item = QTableWidgetItem(postgresql_db.username) + username_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.ui.tablePostgreSqlDbs.setItem(row, 4, username_item) + self.ui.tablePostgreSqlDbs.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents) + # XSL-Ordner Methoden def _add_xsl_dir(self): """Fügt einen neuen XSL-Ordner hinzu.""" @@ -598,6 +635,75 @@ class AppSettingsDlg(QDialog): self._populate_pdf_project_table() + # PostgreSQL Methoden + def _add_postgresql_db(self): + """Fügt eine neue PostgreSQL-Datenbank hinzu.""" + dialog = PostgreSqlConfigDialog(self) + if dialog.exec() == QDialog.DialogCode.Accepted: + data = dialog.get_data() + if data: + new_id = max([x.id for x in self.temp_postgresql_dbs], default=0) + 1 + new_postgresql_db = PostgreSqlDb( + id=new_id, + name=data["name"], + host=data["host"], + port=data["port"], + database=data["database"], + username=data["username"], + password=data["password"] + ) + self.temp_postgresql_dbs.append(new_postgresql_db) + self._populate_postgresql_db_table() + + self.settings.postgresql_dbs = self.temp_postgresql_dbs.copy() + self.settings.save() + + def _remove_postgresql_db(self): + """Entfernt die ausgewählte PostgreSQL-Datenbank.""" + current_row = self.ui.tablePostgreSqlDbs.currentRow() + if current_row >= 0: + del self.temp_postgresql_dbs[current_row] + self._populate_postgresql_db_table() + self._update_postgresql_db_buttons() + + self.settings.postgresql_dbs = self.temp_postgresql_dbs.copy() + self.settings.save() + + def _update_postgresql_db_buttons(self): + """Aktualisiert den Status der PostgreSQL-Buttons.""" + has_selection = self.ui.tablePostgreSqlDbs.currentRow() >= 0 + self.ui.removePostgreSqlDb.setEnabled(has_selection) + + def _edit_postgresql_db(self, index): + """Bearbeitet eine PostgreSQL-Datenbank per Doppelklick.""" + row = index.row() + if 0 <= row < len(self.temp_postgresql_dbs): + postgresql_db = self.temp_postgresql_dbs[row] + dialog = PostgreSqlConfigDialog(self) + + # Vorhandene Daten setzen + data = { + "name": postgresql_db.name, + "host": postgresql_db.host, + "port": postgresql_db.port, + "database": postgresql_db.database, + "username": postgresql_db.username, + "password": postgresql_db.password + } + dialog.set_data(data) + + if dialog.exec() == QDialog.DialogCode.Accepted: + new_data = dialog.get_data() + if new_data: + # Daten aktualisieren + postgresql_db.name = new_data["name"] + postgresql_db.host = new_data["host"] + postgresql_db.port = new_data["port"] + postgresql_db.database = new_data["database"] + postgresql_db.username = new_data["username"] + postgresql_db.password = new_data["password"] + self._populate_postgresql_db_table() + def accept(self): """Übernimmt die Änderungen und schließt den Dialog.""" # Aktualisiere die ursprünglichen Einstellungen diff --git a/src/ui/PostgreSqlConfigDialog.py b/src/ui/PostgreSqlConfigDialog.py index 66ade69..6ecf324 100644 --- a/src/ui/PostgreSqlConfigDialog.py +++ b/src/ui/PostgreSqlConfigDialog.py @@ -2,6 +2,8 @@ from PySide6.QtWidgets import QDialog, QMessageBox from ui.PostgreSqlConfigDialog_ui import Ui_PostgreSqlConfigDialog +import polars as pl + class PostgreSqlConfigDialog(QDialog): """Dialog zur Konfiguration einer PostgreSQL-Datenbank ohne ID.""" @@ -23,12 +25,18 @@ class PostgreSqlConfigDialog(QDialog): """Testet die Datenbankverbindung.""" # Hier könnte eine echte Verbindung getestet werden # Für jetzt zeigen wir nur eine Info-Nachricht - QMessageBox.information( - self, - "Verbindungstest", - "Verbindungstest-Funktionalität noch nicht implementiert.\n" - "Die Eingaben werden gespeichert, wenn Sie auf OK klicken." - ) + data = self.get_data() + + try: + r = pl.read_database_uri( + query="SELECT 1", + uri=f"postgresql://{data['username']}:{data['password']}@{data['host']}:{data['port']}/{data['database']}" + ) + + QMessageBox.information(self, "Verbindungstest", f"Vebindung erfolgreich:\n{str(r)}") + except Exception as e: + QMessageBox.warning(self, "Verbindungstest", f"Verbindung fehlgeschlagen:\n{e}") + raise e def set_data(self, data): """Setzt die Daten in den Dialog.""" diff --git a/uv.lock b/uv.lock index cbbd6e4..e6b94b0 100644 --- a/uv.lock +++ b/uv.lock @@ -37,8 +37,7 @@ name = "documentor" version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "connectorx" }, - { name = "polars" }, + { name = "polars", extra = ["connectorx", "pyarrow"] }, { name = "pydantic-settings" }, { name = "pydantic-yaml" }, { name = "pyqtdarktheme" }, @@ -47,8 +46,7 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "connectorx", specifier = ">=0.4.3" }, - { name = "polars", specifier = ">=1.31.0" }, + { name = "polars", extras = ["connectorx", "pyarrow"], specifier = ">=1.31.0" }, { name = "pydantic-settings", specifier = ">=2.9.1" }, { name = "pydantic-yaml", specifier = ">=1.5.1" }, { name = "pyqtdarktheme", specifier = ">=2.1.0" }, @@ -72,6 +70,40 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/4b/0673a68ac4d6527fac951970e929c3b4440c654f994f0c957bd5556deb38/polars-1.31.0-cp39-abi3-win_arm64.whl", hash = "sha256:62ef23bb9d10dca4c2b945979f9a50812ac4ace4ed9e158a6b5d32a7322e6f75", size = 31469078, upload-time = "2025-06-18T11:59:59.242Z" }, ] +[package.optional-dependencies] +connectorx = [ + { name = "connectorx" }, +] +pyarrow = [ + { name = "pyarrow" }, +] + +[[package]] +name = "pyarrow" +version = "20.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/aa/daa413b81446d20d4dad2944110dcf4cf4f4179ef7f685dd5a6d7570dc8e/pyarrow-20.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a15532e77b94c61efadde86d10957950392999503b3616b2ffcef7621a002893", size = 30798501, upload-time = "2025-04-27T12:30:48.351Z" }, + { url = "https://files.pythonhosted.org/packages/ff/75/2303d1caa410925de902d32ac215dc80a7ce7dd8dfe95358c165f2adf107/pyarrow-20.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:dd43f58037443af715f34f1322c782ec463a3c8a94a85fdb2d987ceb5658e061", size = 32277895, upload-time = "2025-04-27T12:30:55.238Z" }, + { url = "https://files.pythonhosted.org/packages/92/41/fe18c7c0b38b20811b73d1bdd54b1fccba0dab0e51d2048878042d84afa8/pyarrow-20.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa0d288143a8585806e3cc7c39566407aab646fb9ece164609dac1cfff45f6ae", size = 41327322, upload-time = "2025-04-27T12:31:05.587Z" }, + { url = "https://files.pythonhosted.org/packages/da/ab/7dbf3d11db67c72dbf36ae63dcbc9f30b866c153b3a22ef728523943eee6/pyarrow-20.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6953f0114f8d6f3d905d98e987d0924dabce59c3cda380bdfaa25a6201563b4", size = 42411441, upload-time = "2025-04-27T12:31:15.675Z" }, + { url = "https://files.pythonhosted.org/packages/90/c3/0c7da7b6dac863af75b64e2f827e4742161128c350bfe7955b426484e226/pyarrow-20.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:991f85b48a8a5e839b2128590ce07611fae48a904cae6cab1f089c5955b57eb5", size = 40677027, upload-time = "2025-04-27T12:31:24.631Z" }, + { url = "https://files.pythonhosted.org/packages/be/27/43a47fa0ff9053ab5203bb3faeec435d43c0d8bfa40179bfd076cdbd4e1c/pyarrow-20.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:97c8dc984ed09cb07d618d57d8d4b67a5100a30c3818c2fb0b04599f0da2de7b", size = 42281473, upload-time = "2025-04-27T12:31:31.311Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/d56c63b078876da81bbb9ba695a596eabee9b085555ed12bf6eb3b7cab0e/pyarrow-20.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9b71daf534f4745818f96c214dbc1e6124d7daf059167330b610fc69b6f3d3e3", size = 42893897, upload-time = "2025-04-27T12:31:39.406Z" }, + { url = "https://files.pythonhosted.org/packages/92/ac/7d4bd020ba9145f354012838692d48300c1b8fe5634bfda886abcada67ed/pyarrow-20.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8b88758f9303fa5a83d6c90e176714b2fd3852e776fc2d7e42a22dd6c2fb368", size = 44543847, upload-time = "2025-04-27T12:31:45.997Z" }, + { url = "https://files.pythonhosted.org/packages/9d/07/290f4abf9ca702c5df7b47739c1b2c83588641ddfa2cc75e34a301d42e55/pyarrow-20.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:30b3051b7975801c1e1d387e17c588d8ab05ced9b1e14eec57915f79869b5031", size = 25653219, upload-time = "2025-04-27T12:31:54.11Z" }, + { url = "https://files.pythonhosted.org/packages/95/df/720bb17704b10bd69dde086e1400b8eefb8f58df3f8ac9cff6c425bf57f1/pyarrow-20.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ca151afa4f9b7bc45bcc791eb9a89e90a9eb2772767d0b1e5389609c7d03db63", size = 30853957, upload-time = "2025-04-27T12:31:59.215Z" }, + { url = "https://files.pythonhosted.org/packages/d9/72/0d5f875efc31baef742ba55a00a25213a19ea64d7176e0fe001c5d8b6e9a/pyarrow-20.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:4680f01ecd86e0dd63e39eb5cd59ef9ff24a9d166db328679e36c108dc993d4c", size = 32247972, upload-time = "2025-04-27T12:32:05.369Z" }, + { url = "https://files.pythonhosted.org/packages/d5/bc/e48b4fa544d2eea72f7844180eb77f83f2030b84c8dad860f199f94307ed/pyarrow-20.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f4c8534e2ff059765647aa69b75d6543f9fef59e2cd4c6d18015192565d2b70", size = 41256434, upload-time = "2025-04-27T12:32:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/c3/01/974043a29874aa2cf4f87fb07fd108828fc7362300265a2a64a94965e35b/pyarrow-20.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e1f8a47f4b4ae4c69c4d702cfbdfe4d41e18e5c7ef6f1bb1c50918c1e81c57b", size = 42353648, upload-time = "2025-04-27T12:32:20.766Z" }, + { url = "https://files.pythonhosted.org/packages/68/95/cc0d3634cde9ca69b0e51cbe830d8915ea32dda2157560dda27ff3b3337b/pyarrow-20.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:a1f60dc14658efaa927f8214734f6a01a806d7690be4b3232ba526836d216122", size = 40619853, upload-time = "2025-04-27T12:32:28.1Z" }, + { url = "https://files.pythonhosted.org/packages/29/c2/3ad40e07e96a3e74e7ed7cc8285aadfa84eb848a798c98ec0ad009eb6bcc/pyarrow-20.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:204a846dca751428991346976b914d6d2a82ae5b8316a6ed99789ebf976551e6", size = 42241743, upload-time = "2025-04-27T12:32:35.792Z" }, + { url = "https://files.pythonhosted.org/packages/eb/cb/65fa110b483339add6a9bc7b6373614166b14e20375d4daa73483755f830/pyarrow-20.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f3b117b922af5e4c6b9a9115825726cac7d8b1421c37c2b5e24fbacc8930612c", size = 42839441, upload-time = "2025-04-27T12:32:46.64Z" }, + { url = "https://files.pythonhosted.org/packages/98/7b/f30b1954589243207d7a0fbc9997401044bf9a033eec78f6cb50da3f304a/pyarrow-20.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e724a3fd23ae5b9c010e7be857f4405ed5e679db5c93e66204db1a69f733936a", size = 44503279, upload-time = "2025-04-27T12:32:56.503Z" }, + { url = "https://files.pythonhosted.org/packages/37/40/ad395740cd641869a13bcf60851296c89624662575621968dcfafabaa7f6/pyarrow-20.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:82f1ee5133bd8f49d31be1299dc07f585136679666b502540db854968576faf9", size = 25944982, upload-time = "2025-04-27T12:33:04.72Z" }, +] + [[package]] name = "pydantic" version = "2.11.7" @@ -117,16 +149,16 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.9.1" +version = "2.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/ef/3d61472b7801c896f9efd9bb8750977d9577098b05224c5c41820690155e/pydantic_settings-2.10.0.tar.gz", hash = "sha256:7a12e0767ba283954f3fd3fefdd0df3af21b28aa849c40c35811d52d682fa876", size = 172625, upload-time = "2025-06-21T13:56:55.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, + { url = "https://files.pythonhosted.org/packages/7d/9e/fce9331fecf1d2761ff0516c5dceab8a5fd415e82943e727dc4c5fa84a90/pydantic_settings-2.10.0-py3-none-any.whl", hash = "sha256:33781dfa1c7405d5ed2b6f150830a93bb58462a847357bd8f162f8bacb77c027", size = 45232, upload-time = "2025-06-21T13:56:53.682Z" }, ] [[package]]