Skip to content

Commit f6d098c

Browse files
authored
Fix duplicate database mappings when opening, adding or creating databases in DB editor (#3250)
2 parents 403c082 + 3f9da4b commit f6d098c

File tree

6 files changed

+24
-10
lines changed

6 files changed

+24
-10
lines changed

spinetoolbox/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1779,7 +1779,7 @@ def display_byte_size(size_bytes: int) -> tuple[float | int, str]:
17791779

17801780

17811781
def normcase_database_url_path(url: str) -> str:
1782-
if not url.startswith("sqlite://"):
1782+
if not url.startswith("sqlite:///"):
17831783
return url
17841784
path = url[len("sqlite:///") :]
17851785
return "sqlite:///" + os.path.normcase(path)

spinetoolbox/spine_db_editor/widgets/multi_spine_db_editor.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
from PySide6.QtCore import QPoint, Slot
1717
from PySide6.QtGui import QFont, QIcon
1818
from PySide6.QtWidgets import QMenu, QStatusBar, QToolButton
19+
from sqlalchemy.engine.url import URL
1920
from ...config import MAINWINDOW_SS, ONLINE_DOCUMENTATION_URL
2021
from ...font import TOOLBOX_FONT
21-
from ...helpers import CharIconEngine, open_url
22+
from ...helpers import CharIconEngine, normcase_database_url_path, open_url
2223
from ...widgets.multi_tab_window import MultiTabWindow
2324
from ...widgets.settings_widget import SpineDBEditorSettingsWidget
2425
from ..editors import db_editor_registry
@@ -241,7 +242,12 @@ def open_db_editor(db_urls, db_mngr, reuse_existing_editor):
241242
if multi_db_editor.tab_load_success:
242243
multi_db_editor.show()
243244
return
244-
existing = _get_existing_spine_db_editor(list(map(str, db_urls)))
245+
normcased_urls = []
246+
for url in db_urls:
247+
if isinstance(url, URL):
248+
url = url.render_as_string(hide_password=False)
249+
normcased_urls.append(normcase_database_url_path(url))
250+
existing = _get_existing_spine_db_editor(normcased_urls)
245251
if existing is None:
246252
multi_db_editor.add_new_tab(db_urls)
247253
else:

spinetoolbox/spine_db_editor/widgets/spine_db_editor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def open_db_file(self, _=False):
255255
self.qsettings.endGroup()
256256
if not file_path:
257257
return
258-
url = "sqlite:///" + os.path.normcase(file_path)
258+
url = "sqlite:///" + file_path
259259
self.load_db_urls([url])
260260

261261
@Slot(bool)
@@ -267,7 +267,7 @@ def add_db_file(self, _=False):
267267
self.qsettings.endGroup()
268268
if not file_path:
269269
return
270-
url = "sqlite:///" + os.path.normcase(file_path)
270+
url = "sqlite:///" + file_path
271271
self.load_db_urls(self.db_urls + [url])
272272

273273
@Slot()
@@ -283,7 +283,7 @@ def create_db_file(self) -> None:
283283
os.remove(file_path)
284284
except OSError:
285285
pass
286-
url = "sqlite:///" + os.path.normcase(file_path)
286+
url = "sqlite:///" + file_path
287287
self.load_db_urls([url], create=True)
288288

289289
@Slot()

spinetoolbox/spine_db_manager.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
from spinedb_api.temp_id import TempId
6363
from .database_display_names import NameRegistry
6464
from .fetch_parent import FetchParent
65-
from .helpers import DBMapDictItems, DBMapPublicItems, busy_effect, plain_to_tool_tip
65+
from .helpers import DBMapDictItems, DBMapPublicItems, busy_effect, normcase_database_url_path, plain_to_tool_tip
6666
from .mvcmodels.shared import INVALID_TYPE, PARAMETER_TYPE_VALIDATION_ROLE, PARSED_ROLE, TYPE_NOT_VALIDATED, VALID_TYPE
6767
from .parameter_type_validation import ParameterTypeValidator
6868
from .spine_db_commands import (
@@ -297,6 +297,7 @@ def db_map(self, url: str) -> DatabaseMapping:
297297
"""
298298
if isinstance(url, URL):
299299
url = url.render_as_string(hide_password=False)
300+
url = normcase_database_url_path(url)
300301
return self._db_maps.get(url)
301302

302303
def create_new_spine_database(self, url: str, logger: LoggerInterface, overwrite: bool = False):
@@ -324,6 +325,7 @@ def create_new_spine_database(self, url: str, logger: LoggerInterface, overwrite
324325

325326
def close_session(self, url: str) -> None:
326327
"""Pops any db map on the given url and closes its connection."""
328+
url = normcase_database_url_path(url)
327329
self._no_prompt_urls.discard(url)
328330
try:
329331
db_map = self._db_maps.pop(url)
@@ -364,6 +366,7 @@ def get_db_map(
364366
"""
365367
if isinstance(url, URL):
366368
url = url.render_as_string(hide_password=False)
369+
url = normcase_database_url_path(url)
367370
db_map = self._db_maps.get(url)
368371
if db_map is not None:
369372
return db_map
@@ -1433,7 +1436,10 @@ def export_data(
14331436
raise ValueError()
14341437

14351438
def _is_url_available(self, url: Union[URL, str], logger: LoggerInterface) -> bool:
1436-
if str(url) in self.db_urls:
1439+
if isinstance(url, URL):
1440+
url = url.render_as_string(hide_password=False)
1441+
url = normcase_database_url_path(url)
1442+
if url in self.db_urls:
14371443
message = f"The URL <b>{url}</b> is in use. Please close all applications using it and try again."
14381444
logger.msg_error.emit(message)
14391445
return False

tests/spine_db_editor/widgets/test_multi_spine_db_editor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from unittest.mock import MagicMock, patch
1818
from PySide6.QtCore import QPoint, QSettings
1919
from PySide6.QtWidgets import QApplication
20+
from spinetoolbox.helpers import normcase_database_url_path
2021
from spinetoolbox.multi_tab_windows import MultiTabWindowRegistry
2122
from spinetoolbox.spine_db_editor.widgets.multi_spine_db_editor import MultiSpineDBEditor, open_db_editor
2223
from spinetoolbox.spine_db_manager import SpineDBManager
@@ -93,7 +94,7 @@ def test_open_db_in_tab_when_editor_has_an_empty_tab(self):
9394
"spinetoolbox.spine_db_editor.widgets.multi_spine_db_editor.db_editor_registry",
9495
self._db_editor_registry,
9596
),
96-
patch("spinetoolbox.spine_db_editor.widgets.multi_spine_db_editor.MultiSpineDBEditor.show") as mock_show,
97+
patch("spinetoolbox.spine_db_editor.widgets.multi_spine_db_editor.MultiSpineDBEditor.show"),
9798
):
9899
self.assertFalse(self._db_editor_registry.has_windows())
99100
window = MultiSpineDBEditor(self._db_mngr, [])
@@ -103,5 +104,5 @@ def test_open_db_in_tab_when_editor_has_an_empty_tab(self):
103104
open_db_editor([self._db_url], self._db_mngr, reuse_existing_editor=True)
104105
self.assertEqual(window.tab_widget.count(), 2)
105106
tab = window.tab_widget.widget(1)
106-
self.assertEqual(tab.db_urls, [self._db_url])
107+
self.assertEqual(tab.db_urls, [normcase_database_url_path(self._db_url)])
107108
self._close_windows()

tests/test_helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ def test_correctness(self):
551551
class TestNormcaseDatabaseUrlPath:
552552
def test_correctness(self):
553553
assert normcase_database_url_path("mysql://example.com/Path/MY_DB") == "mysql://example.com/Path/MY_DB"
554+
assert normcase_database_url_path("sqlite://") == "sqlite://"
554555
if sys.platform == "win32":
555556
assert (
556557
normcase_database_url_path("sqlite:///C:\\Users\\SansSerif\\in.sqlite")

0 commit comments

Comments
 (0)