Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"specifications": {
"Tool": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"specifications": {},
"connections": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"specifications": {
"Exporter": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"specifications": {
"Tool": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"specifications": {
"Tool": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "Test project to test scenario filtering in a Tool project item.",
"specifications": {
"Importer": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"project": {
"version": 13,
"version": 14,
"description": "",
"settings": {
"enable_execute_all": true
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-e git+https://github.com/spine-tools/Spine-Database-API.git#egg=spinedb_api
-e git+https://github.com/spine-tools/spine-engine.git#egg=spine_engine
-e git+https://github.com/spine-tools/spine-items.git#egg=spine_items
-e git+https://github.com/spine-tools/spine-items.git@toolbox_issue_3029_phase_1#egg=spine_items
-e .
2 changes: 1 addition & 1 deletion spinetoolbox/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from pathlib import Path
import sys

LATEST_PROJECT_VERSION = 13
LATEST_PROJECT_VERSION = 14

# For the Add/Update SpineOpt wizard
REQUIRED_SPINE_OPT_VERSION = "0.10.0"
Expand Down
207 changes: 206 additions & 1 deletion spinetoolbox/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,81 @@
return


def select_file_path(parent, title, initial_path=None, check_file=None):
"""Opens file browser where user can select a file path.

Args:
parent (QWidget): Parent widget for the file dialog and message boxes
title (str): File dialog title
initial_path (str, optional): Initial directory for the file dialog
check_file (str, optional): If given, selected file must begin with the given string

Returns:
str: Full path to the selected file or None if the operation was cancelled or does not match check_file thing.
"""
init_path = initial_path if initial_path is not None else home_dir()

Check warning on line 953 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L953

Added line #L953 was not covered by tests
if sys.platform == "win32":
answer = get_path_from_native_open_file_dialog(parent, init_path, title)

Check warning on line 955 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L955

Added line #L955 was not covered by tests
else:
# noinspection PyCallByClass, PyTypeChecker, PyArgumentList
answer = QFileDialog.getOpenFileName(parent, title, init_path)

Check warning on line 958 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L958

Added line #L958 was not covered by tests
if answer[0] == "": # Canceled (american-english), cancelled (british-english)
return None

Check warning on line 960 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L960

Added line #L960 was not covered by tests
# Check that the selected file name starts with given check_file argument if given
if check_file is not None:
_, selected_file = os.path.split(answer[0])

Check warning on line 963 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L963

Added line #L963 was not covered by tests
if not selected_file.lower().startswith(check_file):
msg = f"Selected file <b>{selected_file}</b> is not a valid {check_file.capitalize()} Executable"

Check warning on line 965 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L965

Added line #L965 was not covered by tests
# noinspection PyCallByClass, PyArgumentList
QMessageBox.warning(parent, f"Invalid {check_file.capitalize()} Executable", msg)
return None
return answer[0]

Check warning on line 969 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L967-L969

Added lines #L967 - L969 were not covered by tests


def select_dir(parent, title, initial_path=None):
"""Shows directory browser and returns the new directory.

Args:
parent (QWidget): Parent of QFileDialog
title (str): Directory browser title
initial_path (str, optional): Initial directory for the directory browser
"""
init_path = initial_path if initial_path is not None else home_dir()
answer = QFileDialog.getExistingDirectory(parent, title, init_path)

Check warning on line 981 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L980-L981

Added lines #L980 - L981 were not covered by tests
if not answer: # Canceled (american-english), cancelled (british-english)
return None
return answer

Check warning on line 984 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L983-L984

Added lines #L983 - L984 were not covered by tests


# def browse_new_python_interpreter(parent, start_dir):
# """Opens file browser where user can select a python interpreter (i.e. python.exe on Windows).
#
# Args:
# parent (QWidget): Parent widget for the file dialog and message boxes
# start_dir (str): Initial path for the file dialog
#
# Returns:
# str: Path to a Python interpreter or None if cancelled
# """
# title = "Select Python Interpreter"
# if sys.platform == "win32":
# answer = get_path_from_native_open_file_dialog(parent, start_dir, title + " (e.g. python.exe on Windows)")
# else:
# initial_path = start_dir if start_dir is not None else home_dir()
# # noinspection PyCallByClass, PyTypeChecker, PyArgumentList
# answer = QFileDialog.getOpenFileName(parent, title, initial_path)
# if answer[0] == "": # Canceled
# return None
# # Check that selected file starts with string 'python'
# _, selected_file = os.path.split(answer[0])
# if not selected_file.lower().startswith("python"):
# msg = f"Selected file <b>{selected_file}</b> is not a valid Python interpreter"
# # noinspection PyCallByClass, PyArgumentList
# QMessageBox.warning(parent, "Invalid Python Interpreter", msg)
# return None
# return answer[0]


def select_conda_executable(parent, line_edit):
"""Opens file browser where user can select a conda executable.

Expand Down Expand Up @@ -1070,7 +1145,7 @@
In addition, can be used to check if the file name in given file path starts with
the given extra_check string. Needed in SettingsWidget and KernelEditor because
the QLineEdits are editable. Returns True when file_path is an empty string so that
we can use default values (e.g. from line edit place holder text). Returns also True
we can use default values (e.g. from line edit placeholder text). Returns also True
when file_path is just 'python' or 'julia' so that user's can use the python or julia
in PATH.

Expand Down Expand Up @@ -1948,3 +2023,133 @@
settings.clear()
s1 = QSettings("SpineProject", "AddUpSpineOptWizard")
s1.clear()


def load_list_of_paths_from_qsettings(qsettings, key):
"""Returns a list of items that are stored in given QSettings
key as a string, where each item is separated by '<>'.

Args:
qsettings (QSettings): Settings object
key (str): Key in QSettings object

Returns:
list: List of strings or an empty list
"""
interpreters = qsettings.value(key, defaultValue=None)
if not interpreters:
return list()
return split_string_to_list(interpreters)

Check warning on line 2042 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2042

Added line #L2042 was not covered by tests


def split_string_to_list(stri):
"""Splits a string where each item is separated by a '<>' into a list."""
item_list = list()
if not stri:
return list()
s = str(stri)
s_list = s.split("<>")

Check warning on line 2051 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2050-L2051

Added lines #L2050 - L2051 were not covered by tests
for item in s_list:
item_list.append(item)
return item_list

Check warning on line 2054 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2053-L2054

Added lines #L2053 - L2054 were not covered by tests


def save_path_to_qsettings(qsettings, key, new_entry):
"""Adds a new entry to the QSettings key that contains a string
which represents a list of strings, where each string is separated
by '<>'.

Args:
qsettings (QSettings): Settings object
key (str): Key in QSettings object
new_entry (str): Item to append to the string

Returns:
list: Updated paths list
"""
paths = qsettings.value(key, defaultValue=None)
if not new_entry:
return split_string_to_list(paths)
if not paths:
paths_list = [new_entry]
updated_paths = new_entry

Check warning on line 2075 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2074-L2075

Added lines #L2074 - L2075 were not covered by tests
else:
paths = str(paths)
paths_list = paths.split("<>")
normalized_paths = list(map(os.path.normcase, paths_list))
try:
index = normalized_paths.index(os.path.normcase(new_entry))
except ValueError:

Check warning on line 2082 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2077-L2082

Added lines #L2077 - L2082 were not covered by tests
# Add new path only if it's not in the list already
paths_list.insert(0, new_entry)

Check warning on line 2084 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2084

Added line #L2084 was not covered by tests
if len(paths_list) > 20:
paths_list.pop()
updated_paths = "<>".join(paths_list)
qsettings.setValue(key, updated_paths) # Save updated paths
qsettings.sync() # Commit change immediately
return paths_list

Check warning on line 2090 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2086-L2090

Added lines #L2086 - L2090 were not covered by tests


def remove_path_from_qsettings(qsettings, key, path_to_remove):
"""Removes a given path from a list of items that are stored in
given QSettings key as a string where each path is separated by '<>'.

Args:
qsettings (QSettings): Settings object
key (str): Key in QSettings object
path (str): Path to remove

Returns:
list: Updated paths list
"""
print(f"Removing {path_to_remove} from key {key}")
paths = qsettings.value(key, defaultValue=None)

Check warning on line 2106 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2105-L2106

Added lines #L2105 - L2106 were not covered by tests
if not paths:
return list()
paths = str(paths)
paths_list = paths.split("<>")

Check warning on line 2110 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2108-L2110

Added lines #L2108 - L2110 were not covered by tests
for entry in paths_list:
if same_path(entry, path_to_remove):
paths_list.pop(paths_list.index(entry))
break
updated_paths = "<>".join(paths_list)
qsettings.setValue(key, updated_paths) # Save updated paths
qsettings.sync() # Commit change immediately
return paths_list

Check warning on line 2118 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2113-L2118

Added lines #L2113 - L2118 were not covered by tests


@Slot()
def restore_override_cursor():
"""Restores default mouse cursor."""
while QApplication.overrideCursor() is not None:
QApplication.restoreOverrideCursor()


def get_current_item(combobox, model):
"""Returns the current item from the given comboBox which uses the given model."""
index = model.index(combobox.currentIndex(), 0)
if not index.isValid():
return None

Check warning on line 2132 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2132

Added line #L2132 was not covered by tests
item = model.itemFromIndex(index)
return item


def get_current_item_data(combobox, model):
"""Returns the data of the current item in the given QComboBox."""
item = get_current_item(combobox, model)
return item.data() if item is not None else None


def path_in_list(p, p_list):
"""Returns True if given path p is in the list of paths. Returns False otherwise."""
for pp in p_list:
if issamefile(p, pp):
return True

Check warning on line 2147 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2147

Added line #L2147 was not covered by tests
return False


def issamefile(a, b):
try:
return os.path.samefile(os.path.realpath(a), os.path.realpath(b))
except FileNotFoundError:
return False

Check warning on line 2155 in spinetoolbox/helpers.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/helpers.py#L2152-L2155

Added lines #L2152 - L2155 were not covered by tests
2 changes: 2 additions & 0 deletions spinetoolbox/kernel_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
kernel_json = os.path.join(kernel_path, "kernel.json")
if not os.path.exists(kernel_json):
return deats
_, kernel_name = os.path.split(kernel_path)

Check warning on line 130 in spinetoolbox/kernel_fetcher.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/kernel_fetcher.py#L130

Added line #L130 was not covered by tests
if os.stat(kernel_json).st_size == 0: # File is empty
return deats
with open(kernel_json, "r") as fh:
Expand All @@ -147,4 +148,5 @@
deats["project"] = arg[10:]
except (KeyError, IndexError):
pass
deats["kernel_name"] = kernel_name

Check warning on line 151 in spinetoolbox/kernel_fetcher.py

View check run for this annotation

Codecov / codecov/patch

spinetoolbox/kernel_fetcher.py#L151

Added line #L151 was not covered by tests
return deats
Loading