Skip to content

Commit 1f6a3f8

Browse files
authored
Merge branch 'main' into its_the_final_logger
2 parents 91afaca + 8e1d44c commit 1f6a3f8

10 files changed

Lines changed: 94 additions & 29 deletions

File tree

activity_browser/actions/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
from .method.method_duplicate import MethodDuplicate
3232
from .method.method_delete import MethodDelete
33+
from .method.method_open import MethodOpen
3334

3435
from .method.cf_uncertainty_modify import CFUncertaintyModify
3536
from .method.cf_amount_modify import CFAmountModify

activity_browser/actions/activity/activity_delete.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,30 @@ def run(activity_keys: List[tuple]):
2727
# retrieve activity objects from the controller using the provided keys
2828
activities = [bd.get_activity(key) for key in activity_keys]
2929

30+
warning_text = f"Are you certain you want to delete {len(activities)} activity/activities?"
31+
3032
# check for downstream processes
3133
if any(len(act.upstream()) > 0 for act in activities):
3234
# warning text
33-
text = (
34-
"One or more activities have downstream processes. Deleting these activities will remove the "
35-
"exchange from the downstream processes, this can't be undone.\n\nAre you sure you want to "
36-
"continue?"
35+
warning_text += (
36+
"\n\nOne or more activities have downstream processes. Deleting these activities will remove the "
37+
"exchange from the downstream processes as well."
3738
)
3839

39-
# alert the user
40-
choice = QtWidgets.QMessageBox.warning(
41-
application.main_window,
42-
"Activity/Activities has/have downstream processes",
43-
text,
44-
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
45-
QtWidgets.QMessageBox.No,
46-
)
40+
# alert the user
41+
choice = QtWidgets.QMessageBox.warning(
42+
application.main_window,
43+
"Deleting activity/activities",
44+
warning_text,
45+
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
46+
QtWidgets.QMessageBox.No,
47+
)
48+
49+
# return if the user cancels
50+
if choice == QtWidgets.QMessageBox.No:
51+
return
52+
4753

48-
# return if the user cancels
49-
if choice == QtWidgets.QMessageBox.No:
50-
return
5154

5255
# use the activity controller to delete multiple activities
5356
for act in activities:

activity_browser/actions/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def get_QButton(cls, *args, **kwargs):
3535
cls.icon,
3636
cls.text
3737
)
38-
button.clicked.connect(lambda x: cls.run(*args, **kwargs))
38+
button.clicked.connect(lambda x: cls.triggered(*args, **kwargs))
3939
return button
4040

4141

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import List
2+
3+
from PySide2 import QtWidgets, QtCore
4+
5+
from activity_browser import signals
6+
from activity_browser.actions.base import ABAction, exception_dialogs
7+
from activity_browser.ui.icons import qicons
8+
9+
10+
class MethodOpen(ABAction):
11+
"""
12+
ABAction to open one or more supplied methods in a method tab by employing signals.
13+
14+
TODO: move away from using signals like this. Probably add a method to the MainWindow to add a panel instead.
15+
"""
16+
17+
icon = qicons.right
18+
text = "Open Impact Category"
19+
20+
@staticmethod
21+
@exception_dialogs
22+
def run(method_names: List[tuple]):
23+
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
24+
for method_name in method_names:
25+
signals.method_selected.emit(method_name)
26+
QtWidgets.QApplication.restoreOverrideCursor()

activity_browser/bwutils/metadata.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -261,26 +261,26 @@ def unpack_classifications(self, df: pd.DataFrame, systems: list) -> pd.DataFram
261261

262262
def _unpacker(self, classifications: list, system: str) -> list:
263263
"""Iterate over all 'c' lists in 'classifications'
264-
and add those matching 'system' to list 'x', when no matches, add empty string.
264+
and add those matching 'system' to list 'system_classifications', when no matches, add empty string.
265265
If 'c' is not a list, add empty string.
266266
267-
Always returns a list 'x' where len(x) == len(classifications).
267+
Always returns a list 'system_classifications' where len(system_classifications) == len(classifications).
268268
269269
Testing showed that converting to list and doing the checks on a list is ~5x faster than keeping
270270
data in DF and using a df.apply() function, we do this now (difference was ~0.4s vs ~2s).
271271
"""
272-
x = []
272+
system_classifications = []
273273
for c in classifications:
274-
cls = ""
275-
if type(c) != list:
276-
x.append(cls)
274+
result = ""
275+
if not isinstance(c, (list, tuple, set)):
276+
system_classifications.append(result)
277277
continue
278278
for s in c:
279279
if s[0] == system:
280-
cls = s[1]
280+
result = s[1]
281281
break
282-
x.append(cls)
283-
return x
282+
system_classifications.append(result) # result is either "" or the classification
283+
return system_classifications
284284

285285

286286
AB_metadata = MetaDataStore()

activity_browser/layouts/tabs/activity.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def __init__(self, key: tuple, read_only=True, parent=None):
167167
self.group_splitter.addWidget(group)
168168
if state := ab_settings.settings.get("activity_table_layout", None):
169169
self.group_splitter.restoreState(bytearray.fromhex(state))
170+
self.group_splitter.setChildrenCollapsible(False)
170171

171172
# Full layout
172173
layout = QtWidgets.QVBoxLayout()

activity_browser/settings.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,25 @@ def __init__(self, filename: str):
7373

7474
super().__init__(ab_dir.user_data_dir, filename)
7575

76+
if not self.healthy():
77+
log.warn("Settings health check failed, resetting")
78+
self.restore_default_settings()
79+
80+
def healthy(self) -> bool:
81+
"""
82+
Checks the settings file to see if it is healthy. Returns True if all checks pass, otherwise returns False.
83+
"""
84+
healthy = True
85+
86+
# check for write access to the current bw dir
87+
healthy = healthy and os.access(self.settings.get("current_bw_dir"), os.W_OK)
88+
89+
# check for write access to the custom bw dirs
90+
access = [os.access(path, os.W_OK) for path in self.settings.get("custom_bw_dirs")]
91+
healthy = healthy and False not in access
92+
93+
return healthy
94+
7695
@staticmethod
7796
def update_old_settings(directory: str, filename: str) -> None:
7897
"""Recycling code to enable backward compatibility: This function is only required for compatibility

activity_browser/ui/tables/LCA_setup.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from PySide2 import QtWidgets
44
from PySide2.QtCore import Qt, Slot
55

6-
from activity_browser import signals
6+
from activity_browser import signals, actions
77
from activity_browser.mod.bw2data import calculation_setups
88

99
from ..icons import qicons
@@ -178,6 +178,8 @@ def __init__(self, parent=None):
178178
"Hold CTRL and click to select multiple rows to open or delete them."
179179
)
180180

181+
self.open_method_action = actions.MethodOpen.get_QAction(self.selected_methods)
182+
181183
def to_python(self):
182184
return self.model.methods
183185

@@ -199,11 +201,14 @@ def contextMenuEvent(self, event) -> None:
199201
if self.indexAt(event.pos()).row() == -1:
200202
return
201203
menu = QtWidgets.QMenu()
204+
205+
menu.addAction(self.open_method_action)
202206
menu.addAction(
203207
qicons.delete,
204-
"Remove row",
208+
"Remove rows",
205209
lambda: self.model.delete_rows(self.selectedIndexes()),
206210
)
211+
207212
menu.exec_(event.globalPos())
208213

209214
def dragEnterEvent(self, event):
@@ -229,6 +234,9 @@ def dropEvent(self, event):
229234
):
230235
self.model.relocateRow(from_index, to_index)
231236

237+
def selected_methods(self):
238+
return [self.model.get_method(p) for p in self.selectedIndexes() if p.column() == 0]
239+
232240

233241
class ScenarioImportTable(ABDataFrameView):
234242
"""Self-contained widget that shows the scenario headers for a given

activity_browser/ui/tables/models/lca_setup.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterable
1+
from typing import Iterable, List, Union
22
from logging import getLogger
33

44
import numpy as np
@@ -195,6 +195,13 @@ def methods(self) -> list:
195195
else self._dataframe.loc[:, "method"].to_list()
196196
)
197197

198+
def get_method(self, proxy: Union[QModelIndex, int]) -> tuple:
199+
"""
200+
Return the method coupled to a model index
201+
"""
202+
idx = self.proxy_to_source(proxy)
203+
return self._dataframe["method"][idx.row()]
204+
198205
def load(self, cs_name: str = None) -> None:
199206
"""
200207
Load a calculation setup defined by cs_name into the methods table.

activity_browser/ui/wizards/db_import_wizard.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ def run_extract_import(self) -> None:
885885
self.downloader.out_path = self.archive_path
886886
with tempfile.TemporaryDirectory() as tempdir:
887887
temp_dir = Path(tempdir)
888-
self.run_extract(tempdir)
888+
self.run_extract(Path(self.archive_path), temp_dir)
889889
if not import_signals.cancel_sentinel:
890890
# Working with ecoinvent 7z file? look for 'datasets' dir
891891
eco_dir = temp_dir.joinpath("datasets")

0 commit comments

Comments
 (0)