From 630e21025f958906481ebf34a11b9afda55cc652 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:28:01 +0200 Subject: [PATCH 01/32] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 18 ++++++++++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 20 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/other.md | 10 ++++++++++ 3 files changed, 48 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/other.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..d7b866801 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,18 @@ +--- +name: Bug report +about: AB is not working as it should be +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +What happened? What did you expect to happen? If there are errors in the terminal, please let us know those. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. +Please add the terminal output from `conda list` here to help us find problems in your environment. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 000000000..1032b94c5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: I have an idea to improve AB +title: '' +labels: feature request +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md new file mode 100644 index 000000000..f65d4948d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.md @@ -0,0 +1,10 @@ +--- +name: Other +about: There is something else I want to share with the AB developers +title: '' +labels: '' +assignees: '' + +--- + + From ac6bbd5897528eae1003dd129e1fae30c92a5ba6 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:39:04 +0200 Subject: [PATCH 02/32] Create config.yml Add issue config --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..7adb66359 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Need help with using AB? + url: https://github.com/LCA-ActivityBrowser/activity-browser/discussions + about: Please ask and answer questions here. From e3e891d07b0be3d171154731fe99c4e214ba4a01 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:41:15 +0200 Subject: [PATCH 03/32] Delete .github/ISSUE_TEMPLATE/other.md Delete other option for github templates --- .github/ISSUE_TEMPLATE/other.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/other.md diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md deleted file mode 100644 index f65d4948d..000000000 --- a/.github/ISSUE_TEMPLATE/other.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Other -about: There is something else I want to share with the AB developers -title: '' -labels: '' -assignees: '' - ---- - - From b78c761bfa60c3e05268ddc15cda54c1c8ba2413 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:51:03 +0200 Subject: [PATCH 04/32] Create bug_report.yml Add burg-report yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..3aad133a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,39 @@ +name: Bug Report +description: AB is not working as it should be +title: +labels: ["bug"] +projects: +assignees: +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what happened + value: + validations: + required: true + - type: textarea + id: errors + attributes: + label: Relevant errors + description: Please copy and paste any relevant errors from the terminal. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: textarea + id: files + attributes: + label: Relevant files + description: Drag any files into this box like screenshots or relevant databases + placeholder: Share your files + value: + - type: textarea + id: conda-env + attributes: + label: Conda environment + description: Please copy and paste the output from `conda list`. This will be automatically formatted into code, so no need for backticks. + render: shell From 0367af7186723365b4d4108f3e9e7b47765b8400 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:52:46 +0200 Subject: [PATCH 05/32] Delete .github/ISSUE_TEMPLATE/bug_report.md delete bug report md version --- .github/ISSUE_TEMPLATE/bug_report.md | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index d7b866801..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Bug report -about: AB is not working as it should be -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -What happened? What did you expect to happen? If there are errors in the terminal, please let us know those. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. -Please add the terminal output from `conda list` here to help us find problems in your environment. From 2af0fdbf460aca559fd2ce8dc25c1e327641a8df Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 10:55:41 +0200 Subject: [PATCH 06/32] Update bug_report.yml Remove unused fields --- .github/ISSUE_TEMPLATE/bug_report.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3aad133a2..2230c2ee7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,9 +1,6 @@ name: Bug Report description: AB is not working as it should be -title: -labels: ["bug"] -projects: -assignees: +labels: ["bug"] body: - type: markdown attributes: From 9562c00f367aaa432cfd4d17cf5beff7aab77492 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:08:48 +0200 Subject: [PATCH 07/32] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2230c2ee7..4d64790d3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ -name: Bug Report -description: AB is not working as it should be +name: Bug report +description: AB is not working as it should be. labels: ["bug"] body: - type: markdown @@ -12,25 +12,25 @@ body: label: What happened? description: Also tell us, what did you expect to happen? placeholder: Tell us what happened - value: validations: required: true - type: textarea id: errors attributes: label: Relevant errors - description: Please copy and paste any relevant errors from the terminal. This will be automatically formatted into code, so no need for backticks. - render: shell + description: Please copy and paste any relevant errors from the terminal. + placeholder: This will be automatically formatted into code, so no need for backticks. + render: python - type: textarea id: files attributes: label: Relevant files - description: Drag any files into this box like screenshots or relevant databases + description: Drag any relevant files into the box below like screenshots or relevant databases placeholder: Share your files - value: - type: textarea id: conda-env attributes: label: Conda environment - description: Please copy and paste the output from `conda list`. This will be automatically formatted into code, so no need for backticks. + description: Please copy and paste the output from `conda list`. + placeholder: This will be automatically formatted into code, so no need for backticks. render: shell From 282d8bdd01b3af12d262ff92ff0fcf6a3246035e Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:32:41 +0200 Subject: [PATCH 08/32] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 4d64790d3..9722302cf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report -description: AB is not working as it should be. -labels: ["bug"] +description: File a bug report for AB. +labels: ["bug"] body: - type: markdown attributes: @@ -19,7 +19,7 @@ body: attributes: label: Relevant errors description: Please copy and paste any relevant errors from the terminal. - placeholder: This will be automatically formatted into code, so no need for backticks. + placeholder: This will be automatically formatted into code, so no need to worry about the formatting. render: python - type: textarea id: files @@ -32,5 +32,5 @@ body: attributes: label: Conda environment description: Please copy and paste the output from `conda list`. - placeholder: This will be automatically formatted into code, so no need for backticks. + placeholder: This will be automatically formatted into code, so no need to worry about the formatting. render: shell From 24d33c431a6b470d74e9e78c40f820a025b4a7f0 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:33:17 +0200 Subject: [PATCH 09/32] Update and rename feature-request.md to feature-request.yml --- .github/ISSUE_TEMPLATE/feature-request.md | 20 -------------------- .github/ISSUE_TEMPLATE/feature-request.yml | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md deleted file mode 100644 index 1032b94c5..000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: I have an idea to improve AB -title: '' -labels: feature request -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 000000000..4ddff49ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,15 @@ +name: Feature request +description: File a feature request for AB. +labels: ["feature request"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! + - type: textarea + id: feature + attributes: + label: Feature request + description: A clear description of your idea and what problem it should resolve. Please share examples or images if relevant. + validations: + required: true From fb522aca1501d94a665142170592e97cc3945f05 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:33:45 +0200 Subject: [PATCH 10/32] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7adb66359..ffeaa5719 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - name: Need help with using AB? url: https://github.com/LCA-ActivityBrowser/activity-browser/discussions - about: Please ask and answer questions here. + about: Please ask AB user questions on our discussions page. From 695cd35aa377775bfb378579c70aeab62101b589 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:34:26 +0200 Subject: [PATCH 11/32] Create something_else.yml --- .github/ISSUE_TEMPLATE/something_else.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/something_else.yml diff --git a/.github/ISSUE_TEMPLATE/something_else.yml b/.github/ISSUE_TEMPLATE/something_else.yml new file mode 100644 index 000000000..73d1cfbb5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/something_else.yml @@ -0,0 +1,14 @@ +name: Something else +description: Open an issue for AB. +body: + - type: markdown + attributes: + value: | + Thanks for sharing this issue with us! In case you want help with using AB, please use the [discussions page](https://github.com/LCA-ActivityBrowser/activity-browser/discussions) instead. + - type: textarea + id: issue + attributes: + label: Issue + description: Please share the issue you're experiencing. + validations: + required: true From 94accf49cdbde319d9b23c14afa673d9cdc74e99 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 11:35:52 +0200 Subject: [PATCH 12/32] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index ffeaa5719..a3942dc9d 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Need help with using AB? + - name: Using AB url: https://github.com/LCA-ActivityBrowser/activity-browser/discussions - about: Please ask AB user questions on our discussions page. + about: Ask AB user questions on our discussions page. From 7e381ab76e5c2c46aaf74382937e6462c5a6bfeb Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:47:56 +0200 Subject: [PATCH 13/32] Create bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report2.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml new file mode 100644 index 000000000..e06853409 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -0,0 +1,48 @@ +name: Bug report +description: File a bug report for AB. +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: checkboxes + id: has-updated + attributes: + label: Updating AB + description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? + options: + - label: Yes + - label: No + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? You can share relevant files (e.g. screenshots/databases) here too. + placeholder: Tell us what happened + validations: + required: true + - type: textarea + id: errors + attributes: + label: Relevant errors + description: Please copy and paste any relevant errors from the terminal. + placeholder: This will be automatically formatted into code, so no need to worry about the formatting. + render: python + - type: dropdown + id: os + attributes: + label: Operating system + multiple: false + options: + - Windows 10 + - Windows 11 + - MacOS + - Linux/Other (please specify below) + - type: textarea + id: conda-env + attributes: + label: Conda environment + description: Please copy and paste the output from `conda list`. + placeholder: This will be automatically formatted into code, so no need to worry about the formatting. + render: shell From a8c11e44416081a7f90dd725390d48ed1ac9668e Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:48:38 +0200 Subject: [PATCH 14/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index e06853409..6e3142e62 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -1,4 +1,4 @@ -name: Bug report +name: Bug report2 description: File a bug report for AB. labels: ["bug"] body: From ba06d8ef3b538c5a1dc9ce00103735a18e252139 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:49:56 +0200 Subject: [PATCH 15/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index 6e3142e62..f5d7f4e9c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -12,8 +12,8 @@ body: label: Updating AB description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? options: - - label: Yes - - label: No + - Yes + - No - type: textarea id: what-happened attributes: From 1fb25fa2174ec62167f7a26738fa6d53edf62ed7 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:50:39 +0200 Subject: [PATCH 16/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index f5d7f4e9c..a46769ab2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -12,8 +12,8 @@ body: label: Updating AB description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? options: - - Yes - - No + - Label: "Yes" + - Label: "No" - type: textarea id: what-happened attributes: From a38febcd7b40e80ba3e7cfdd87e367dd003497e2 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:52:36 +0200 Subject: [PATCH 17/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index a46769ab2..b021e53f8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -12,8 +12,8 @@ body: label: Updating AB description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? options: - - Label: "Yes" - - Label: "No" + - label: Yes + - label: No - type: textarea id: what-happened attributes: From 7323bcd83326d36130d99d035227440abd8e63bc Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:54:24 +0200 Subject: [PATCH 18/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index b021e53f8..0ad78c657 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -12,8 +12,8 @@ body: label: Updating AB description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? options: - - label: Yes - - label: No + - label: "Yes" + - label: "No" - type: textarea id: what-happened attributes: From 6bad693655f65df000c1ee69e36be891fd8768e4 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 16:58:52 +0200 Subject: [PATCH 19/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index 0ad78c657..db6c9d386 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -10,10 +10,8 @@ body: id: has-updated attributes: label: Updating AB - description: Have you tried to fix your issue by [updating AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab)? options: - - label: "Yes" - - label: "No" + - label: "I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) to the newest version and I still have this problem" - type: textarea id: what-happened attributes: @@ -38,7 +36,8 @@ body: - Windows 10 - Windows 11 - MacOS - - Linux/Other (please specify below) + - Linux/Other (please specify above) + default: 0 - type: textarea id: conda-env attributes: From c525d397899872411e8b3372dfa503e811842714 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 17:00:54 +0200 Subject: [PATCH 20/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index db6c9d386..c8a3c0a88 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -1,4 +1,4 @@ -name: Bug report2 +name: Bug report description: File a bug report for AB. labels: ["bug"] body: @@ -11,7 +11,7 @@ body: attributes: label: Updating AB options: - - label: "I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) to the newest version and I still have this problem" + - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) and still experience this issue" - type: textarea id: what-happened attributes: From 6d209825955c04303ef3e0cd5cd555c41c994a80 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 17:01:41 +0200 Subject: [PATCH 21/32] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9722302cf..21058f442 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,4 +1,4 @@ -name: Bug report +name: Bug report OLD description: File a bug report for AB. labels: ["bug"] body: From fb41bbca10279148a047bf1b65fdd7aba5aa7be3 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 17:07:44 +0200 Subject: [PATCH 22/32] Delete .github/ISSUE_TEMPLATE/bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 36 --------------------------- 1 file changed, 36 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 21058f442..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Bug report OLD -description: File a bug report for AB. -labels: ["bug"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: textarea - id: what-happened - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? - placeholder: Tell us what happened - validations: - required: true - - type: textarea - id: errors - attributes: - label: Relevant errors - description: Please copy and paste any relevant errors from the terminal. - placeholder: This will be automatically formatted into code, so no need to worry about the formatting. - render: python - - type: textarea - id: files - attributes: - label: Relevant files - description: Drag any relevant files into the box below like screenshots or relevant databases - placeholder: Share your files - - type: textarea - id: conda-env - attributes: - label: Conda environment - description: Please copy and paste the output from `conda list`. - placeholder: This will be automatically formatted into code, so no need to worry about the formatting. - render: shell From 1082065b832556fdb078d5a4fba433dec90339d3 Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 18:01:02 +0200 Subject: [PATCH 23/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index c8a3c0a88..6a93a9c20 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -11,7 +11,7 @@ body: attributes: label: Updating AB options: - - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) and still experience this issue" + - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) to [![Anaconda-Server Badge](https://anaconda.org/conda-forge/activity-browser/badges/version.svg)](https://anaconda.org/conda-forge/activity-browser) and still experience this issue" - type: textarea id: what-happened attributes: From 52f1b71ca2119f3ae35464742307c62bde7e67ea Mon Sep 17 00:00:00 2001 From: Marc van der Meide Date: Thu, 14 Sep 2023 18:02:12 +0200 Subject: [PATCH 24/32] Update bug_report2.yml --- .github/ISSUE_TEMPLATE/bug_report2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml index 6a93a9c20..c8a3c0a88 100644 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ b/.github/ISSUE_TEMPLATE/bug_report2.yml @@ -11,7 +11,7 @@ body: attributes: label: Updating AB options: - - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) to [![Anaconda-Server Badge](https://anaconda.org/conda-forge/activity-browser/badges/version.svg)](https://anaconda.org/conda-forge/activity-browser) and still experience this issue" + - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) and still experience this issue" - type: textarea id: what-happened attributes: From 0cc83bf1f45a563a8bc4b426671888099a42463b Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Fri, 15 Sep 2023 08:40:58 +0200 Subject: [PATCH 25/32] Rudimentary version checking --- activity_browser/application.py | 3 +++ activity_browser/utils.py | 35 ++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/activity_browser/application.py b/activity_browser/application.py index 0d5cda64d..d4d18faee 100644 --- a/activity_browser/application.py +++ b/activity_browser/application.py @@ -4,6 +4,7 @@ from .controllers import controllers from .layouts import MainWindow from .logger import ABHandler +from .utils import UpdateManager logger = logging.getLogger('ab_logs') log = ABHandler.setup_with_logger(logger, __name__) @@ -23,6 +24,8 @@ def __init__(self): for attr, controller in controllers.items(): setattr(self, attr, controller(self.main_window)) + update_manager = UpdateManager() + def show(self): self.main_window.showMaximized() diff --git a/activity_browser/utils.py b/activity_browser/utils.py index c02a029f4..8548bbf5e 100644 --- a/activity_browser/utils.py +++ b/activity_browser/utils.py @@ -1,10 +1,15 @@ from pathlib import Path import os +import requests +from requests.exceptions import ConnectionError +import pandas as pd +import io from PySide2 import QtWidgets from bw2data.filesystem import safe_filename from .settings import ab_settings +from .info import __version__ def get_base_path() -> Path: @@ -31,4 +36,32 @@ def savefilepath(default_file_name: str = "AB_file", file_filter: str = "All Fil dir=os.path.join(ab_settings.data_dir, safe_name), filter=file_filter, ) - return filepath \ No newline at end of file + return filepath + +class UpdateManager(): + def __init__(self): + self.conda_forge_url = "https://anaconda.org/conda-forge/activity-browser/labels" + + cu = self.current_version + la = self.fetch_latest() + + print('the current version of AB is >{}<, the latest version of AB is >{}<'.format(cu, la)) + + def fetch_latest(self) -> str: + """Fetch the latest version number from conda forge.""" + try: + page = requests.get(self.conda_forge_url) # retrieve the page from the URL + df = pd.read_html(io.StringIO(page.text))[0] # read the version table from the HTML + latest = df.iloc[0, 1] + except ConnectionError as e: # failing to connect to server + # TODO log error properly and handle it properly + latest = '0.0.0' + except: # failing to read the version from the page + # TODO log error properly and handle it properly + latest = '0.0.0' + return latest + + @property + def current_version(self) -> str: + """Version of AB running now""" + return __version__ From 6eb215be450d8470d1f18e28dc1bc44eff87eeb7 Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Fri, 15 Sep 2023 08:43:56 +0200 Subject: [PATCH 26/32] Revert accidental commit to master --- activity_browser/application.py | 3 --- activity_browser/utils.py | 35 +-------------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/activity_browser/application.py b/activity_browser/application.py index d4d18faee..0d5cda64d 100644 --- a/activity_browser/application.py +++ b/activity_browser/application.py @@ -4,7 +4,6 @@ from .controllers import controllers from .layouts import MainWindow from .logger import ABHandler -from .utils import UpdateManager logger = logging.getLogger('ab_logs') log = ABHandler.setup_with_logger(logger, __name__) @@ -24,8 +23,6 @@ def __init__(self): for attr, controller in controllers.items(): setattr(self, attr, controller(self.main_window)) - update_manager = UpdateManager() - def show(self): self.main_window.showMaximized() diff --git a/activity_browser/utils.py b/activity_browser/utils.py index 8548bbf5e..c02a029f4 100644 --- a/activity_browser/utils.py +++ b/activity_browser/utils.py @@ -1,15 +1,10 @@ from pathlib import Path import os -import requests -from requests.exceptions import ConnectionError -import pandas as pd -import io from PySide2 import QtWidgets from bw2data.filesystem import safe_filename from .settings import ab_settings -from .info import __version__ def get_base_path() -> Path: @@ -36,32 +31,4 @@ def savefilepath(default_file_name: str = "AB_file", file_filter: str = "All Fil dir=os.path.join(ab_settings.data_dir, safe_name), filter=file_filter, ) - return filepath - -class UpdateManager(): - def __init__(self): - self.conda_forge_url = "https://anaconda.org/conda-forge/activity-browser/labels" - - cu = self.current_version - la = self.fetch_latest() - - print('the current version of AB is >{}<, the latest version of AB is >{}<'.format(cu, la)) - - def fetch_latest(self) -> str: - """Fetch the latest version number from conda forge.""" - try: - page = requests.get(self.conda_forge_url) # retrieve the page from the URL - df = pd.read_html(io.StringIO(page.text))[0] # read the version table from the HTML - latest = df.iloc[0, 1] - except ConnectionError as e: # failing to connect to server - # TODO log error properly and handle it properly - latest = '0.0.0' - except: # failing to read the version from the page - # TODO log error properly and handle it properly - latest = '0.0.0' - return latest - - @property - def current_version(self) -> str: - """Version of AB running now""" - return __version__ + return filepath \ No newline at end of file From 5ff7146fe325ab3cc01aed20b540bc05646ea0bd Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Fri, 22 Sep 2023 11:42:36 +0200 Subject: [PATCH 27/32] Remove unused template files --- .github/ISSUE_TEMPLATE/bug_report2.yml | 47 ---------------------- .github/ISSUE_TEMPLATE/feature-request.yml | 15 ------- 2 files changed, 62 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report2.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report2.yml b/.github/ISSUE_TEMPLATE/bug_report2.yml deleted file mode 100644 index c8a3c0a88..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report2.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Bug report -description: File a bug report for AB. -labels: ["bug"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: checkboxes - id: has-updated - attributes: - label: Updating AB - options: - - label: "Yes, I have [updated AB](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab) and still experience this issue" - - type: textarea - id: what-happened - attributes: - label: What happened? - description: Also tell us, what did you expect to happen? You can share relevant files (e.g. screenshots/databases) here too. - placeholder: Tell us what happened - validations: - required: true - - type: textarea - id: errors - attributes: - label: Relevant errors - description: Please copy and paste any relevant errors from the terminal. - placeholder: This will be automatically formatted into code, so no need to worry about the formatting. - render: python - - type: dropdown - id: os - attributes: - label: Operating system - multiple: false - options: - - Windows 10 - - Windows 11 - - MacOS - - Linux/Other (please specify above) - default: 0 - - type: textarea - id: conda-env - attributes: - label: Conda environment - description: Please copy and paste the output from `conda list`. - placeholder: This will be automatically formatted into code, so no need to worry about the formatting. - render: shell diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml deleted file mode 100644 index 4ddff49ce..000000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Feature request -description: File a feature request for AB. -labels: ["feature request"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this feature request! - - type: textarea - id: feature - attributes: - label: Feature request - description: A clear description of your idea and what problem it should resolve. Please share examples or images if relevant. - validations: - required: true From d000f1267c4a7071d684af96dc105449ae3adbf0 Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Fri, 22 Sep 2023 15:02:49 +0200 Subject: [PATCH 28/32] Set up signals infrascructure --- activity_browser/controllers/activity.py | 40 +++++++++++++++++++ activity_browser/signals.py | 1 + activity_browser/ui/tables/inventory.py | 21 ++++++++++ .../ui/tables/models/inventory.py | 3 ++ 4 files changed, 65 insertions(+) diff --git a/activity_browser/controllers/activity.py b/activity_browser/controllers/activity.py index 50e13648f..50a8650c1 100644 --- a/activity_browser/controllers/activity.py +++ b/activity_browser/controllers/activity.py @@ -25,6 +25,7 @@ def __init__(self, parent=None): signals.delete_activity.connect(self.delete_activity) signals.delete_activities.connect(self.delete_activity) signals.duplicate_activity.connect(self.duplicate_activity) + signals.duplicate_activity_new_loc.connect(self.duplicate_activity_new_loc) signals.duplicate_activities.connect(self.duplicate_activity) signals.duplicate_to_db_interface.connect(self.show_duplicate_to_db_interface) signals.duplicate_to_db_interface_multiple.connect(self.show_duplicate_to_db_interface) @@ -139,6 +140,45 @@ def duplicate_activity(self, data: Union[tuple, Iterator[tuple]]) -> None: signals.database_changed.emit(db) signals.databases_changed.emit() + @Slot(tuple, name="copyActivityNewLoc") + def duplicate_activity_new_loc(self, data: tuple) -> None: + """Duplicates the selected activity in the same db, links to new location, with a new BW code. + + This function will try and link all exchanges in the same location as the production process + to a chosen location, if none is available for the given exchange, it will try to link to + RoW and then GLO, if those don't exist, the exchange is not altered. + """ + #TODO actually write def, this is just a copy of duplicate_activity above + activities = self._retrieve_activities(data) + + # See also https://github.com/LCA-ActivityBrowser/activity-browser/issues/1042 for what to do + # get list of dependent databases for activity and load to MetaDataStore + # get list of all unique locations in the dependent databases + # trigger dialog with autocomplete-writeable-dropdown-list (sorted alphabetically) + # check every exchange (act.technosphere) whether it can be replaced + # write a def that tries to find the processes and potential alternatives + + for act in activities: + new_code = self.generate_copy_code(act.key) + new_act = act.copy(new_code) + # Update production exchanges + for exc in new_act.production(): + if exc.input.key == act.key: + exc.input = new_act + exc.save() + # Update 'products' + for product in new_act.get('products', []): + if product.get('input') == act.key: + product['input'] = new_act.key + new_act.save() + AB_metadata.update_metadata(new_act.key) + signals.safe_open_activity_tab.emit(new_act.key) + + db = next(iter(activities)).get("database") + bw.databases.set_modified(db) + signals.database_changed.emit(db) + signals.databases_changed.emit() + @Slot(tuple, str, name="copyActivityToDbInterface") @Slot(list, str, name="copyActivitiesToDbInterface") def show_duplicate_to_db_interface(self, data: Union[tuple, Iterator[tuple]], diff --git a/activity_browser/signals.py b/activity_browser/signals.py index 25d8ae651..5eb4a15ab 100644 --- a/activity_browser/signals.py +++ b/activity_browser/signals.py @@ -44,6 +44,7 @@ class Signals(QObject): new_activity = Signal(str) # Trigger dialog to create a new activity in this database | name of database add_activity_to_history = Signal(tuple) # Add this activity to history | key of activity duplicate_activity = Signal(tuple) # Duplicate this activity | key of activity + duplicate_activity_new_loc = Signal(tuple) # Duplicate this activity to a new location | key of activity duplicate_activities = Signal(list) # Duplicate these activities | list of activity keys duplicate_activity_to_db = Signal(str, object) # Duplicate this activity to another database | name of target database, BW2 actiivty object #TODO write below 2 signals to work without the str, source database is already stored in activity keys diff --git a/activity_browser/ui/tables/inventory.py b/activity_browser/ui/tables/inventory.py index cf5cda4d2..4fa225c6b 100644 --- a/activity_browser/ui/tables/inventory.py +++ b/activity_browser/ui/tables/inventory.py @@ -113,6 +113,12 @@ def __init__(self, parent=None): self.duplicate_activity_action = QtWidgets.QAction( qicons.copy, "Duplicate activity/-ies", None ) + self.duplicate_activity_new_loc_action = QtWidgets.QAction( + qicons.copy, "Duplicate activity to new location", None + ) + self.duplicate_activity_new_loc_action.setToolTip( + "Duplicate this activity to another location.\n" + "Link the exchanges to a new location if it is availabe.") self.delete_activity_action = QtWidgets.QAction( qicons.delete, "Delete activity/-ies", None ) @@ -135,6 +141,13 @@ def contextMenuEvent(self, event) -> None: if self.indexAt(event.pos()).row() == -1 and len(self.model._dataframe) != 0: return + if self.selectedIndexes() > 1: + act = 'activities' + else: + act = 'activity' + self.duplicate_activity_action.setText("Duplicate {}".format(act)) + self.delete_activity_action.setText("Delete {}".format(act)) + menu = QtWidgets.QMenu() if len(self.model._dataframe) == 0: # if the database is empty, only add the 'new' activity option and return @@ -151,6 +164,9 @@ def contextMenuEvent(self, event) -> None: ) menu.addAction(self.new_activity_action) menu.addAction(self.duplicate_activity_action) + menu.addAction(self.duplicate_activity_new_loc_action) + if len(self.selectedIndexes()) > 1: + self.duplicate_activity_new_loc_action.setEnabled(False) menu.addAction(self.delete_activity_action) menu.addAction( qicons.edit, "Relink the activity exchanges", @@ -176,6 +192,7 @@ def connect_signals(self): lambda: signals.new_activity.emit(self.database_name) ) self.duplicate_activity_action.triggered.connect(self.duplicate_activities) + self.duplicate_activity_new_loc_action.triggered.connect(self.duplicate_activity_to_new_loc) self.delete_activity_action.triggered.connect(self.delete_activities) self.copy_exchanges_for_SDF_action.triggered.connect(self.copy_exchanges_for_SDF) self.doubleClicked.connect(self.open_activity_tab) @@ -217,6 +234,10 @@ def delete_activities(self) -> None: def duplicate_activities(self) -> None: self.model.duplicate_activities(self.selectedIndexes()) + @Slot(name="duplicateActivitiesToNewLocWithinDb") + def duplicate_activity_to_new_loc(self) -> None: + self.model.duplicate_activity_to_new_loc(self.selectedIndexes()) + @Slot(name="duplicateActivitiesToOtherDb") def duplicate_activities_to_db(self) -> None: self.model.duplicate_activities_to_db(self.selectedIndexes()) diff --git a/activity_browser/ui/tables/models/inventory.py b/activity_browser/ui/tables/models/inventory.py index 10790ec0f..a0495d416 100644 --- a/activity_browser/ui/tables/models/inventory.py +++ b/activity_browser/ui/tables/models/inventory.py @@ -185,6 +185,9 @@ def duplicate_activities(self, proxies: list) -> None: else: signals.duplicate_activity.emit(self.get_key(proxies[0])) + def duplicate_activity_to_new_loc(self, proxies: list) -> None: + signals.duplicate_activity_new_loc.emit(self.get_key(proxies[0])) + def duplicate_activities_to_db(self, proxies: list) -> None: if len(proxies) > 1: keys = [self.get_key(p) for p in proxies] From 86922c1578c9d9d9fd034a7048bc9c74fae20e4a Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Sat, 23 Sep 2023 12:06:31 +0200 Subject: [PATCH 29/32] Implement dialog --- activity_browser/controllers/activity.py | 75 ++++++++++++++++-------- activity_browser/ui/tables/inventory.py | 2 +- activity_browser/ui/widgets/__init__.py | 2 +- activity_browser/ui/widgets/dialog.py | 69 ++++++++++++++++++++++ 4 files changed, 122 insertions(+), 26 deletions(-) diff --git a/activity_browser/controllers/activity.py b/activity_browser/controllers/activity.py index 50a8650c1..33b88ae79 100644 --- a/activity_browser/controllers/activity.py +++ b/activity_browser/controllers/activity.py @@ -12,7 +12,7 @@ from activity_browser.settings import project_settings from activity_browser.signals import signals from activity_browser.ui.wizards import UncertaintyWizard -from ..ui.widgets import ActivityLinkingDialog, ActivityLinkingResultsDialog +from ..ui.widgets import ActivityLinkingDialog, ActivityLinkingResultsDialog, LocationLinkingDialog from .parameter import ParameterController @@ -149,35 +149,62 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: RoW and then GLO, if those don't exist, the exchange is not altered. """ #TODO actually write def, this is just a copy of duplicate_activity above + #TODO write such that it takes only one activity as input activities = self._retrieve_activities(data) - # See also https://github.com/LCA-ActivityBrowser/activity-browser/issues/1042 for what to do # get list of dependent databases for activity and load to MetaDataStore - # get list of all unique locations in the dependent databases - # trigger dialog with autocomplete-writeable-dropdown-list (sorted alphabetically) - # check every exchange (act.technosphere) whether it can be replaced - # write a def that tries to find the processes and potential alternatives + databases = [] for act in activities: - new_code = self.generate_copy_code(act.key) - new_act = act.copy(new_code) - # Update production exchanges - for exc in new_act.production(): - if exc.input.key == act.key: - exc.input = new_act - exc.save() - # Update 'products' - for product in new_act.get('products', []): - if product.get('input') == act.key: - product['input'] = new_act.key - new_act.save() - AB_metadata.update_metadata(new_act.key) - signals.safe_open_activity_tab.emit(new_act.key) + for exch in act.technosphere(): + databases.append(exch['input'][0]) + + # load all dependent databases to MetaDataStore + dbs = [AB_metadata.get_database_metadata(db) for db in databases] + # get list of all unique locations in the dependent databases (sorted alphabetically) + locations = [] + for db in dbs: + locations += db['location'].to_list() # add all locations to one list + locations = list(set(locations)) # reduce the list to only unique items + locations.sort() + + # get the location to relink + db = AB_metadata.get_database_metadata(act.key[0]) + old_location = db.loc[db['key'] == act.key]['location'][0] + + # trigger dialog with autocomplete-writeable-dropdown-list + options = (old_location, locations) + dialog = LocationLinkingDialog.relink_location(options, self.window) + relinking_results = dict() + if dialog.exec_() == LocationLinkingDialog.Accepted: + for old, new in dialog.relink.items(): + relinking_results[old] = new + use_alternatives = dialog.use_alternatives_checkbox.isChecked() - db = next(iter(activities)).get("database") - bw.databases.set_modified(db) - signals.database_changed.emit(db) - signals.databases_changed.emit() + # check every exchange (act.technosphere) whether it can be replaced + # write a def that tries to find the processes and potential alternatives + # use MetaDataStore to quickly find things + + # for act in activities: + # new_code = self.generate_copy_code(act.key) + # new_act = act.copy(new_code) + # # Update production exchanges + # for exc in new_act.production(): + # if exc.input.key == act.key: + # exc.input = new_act + # exc.save() + # # Update 'products' + # for product in new_act.get('products', []): + # if product.get('input') == act.key: + # product['input'] = new_act.key + # new_act.save() + # AB_metadata.update_metadata(new_act.key) + # signals.safe_open_activity_tab.emit(new_act.key) + # + # db = next(iter(activities)).get("database") + # bw.databases.set_modified(db) + # signals.database_changed.emit(db) + # signals.databases_changed.emit() @Slot(tuple, str, name="copyActivityToDbInterface") @Slot(list, str, name="copyActivitiesToDbInterface") diff --git a/activity_browser/ui/tables/inventory.py b/activity_browser/ui/tables/inventory.py index 4fa225c6b..19a1b9907 100644 --- a/activity_browser/ui/tables/inventory.py +++ b/activity_browser/ui/tables/inventory.py @@ -141,7 +141,7 @@ def contextMenuEvent(self, event) -> None: if self.indexAt(event.pos()).row() == -1 and len(self.model._dataframe) != 0: return - if self.selectedIndexes() > 1: + if len(self.selectedIndexes()) > 1: act = 'activities' else: act = 'activity' diff --git a/activity_browser/ui/widgets/__init__.py b/activity_browser/ui/widgets/__init__.py index 6b1e64895..bf8798009 100644 --- a/activity_browser/ui/widgets/__init__.py +++ b/activity_browser/ui/widgets/__init__.py @@ -9,7 +9,7 @@ DatabaseLinkingDialog, DefaultBiosphereDialog, DatabaseLinkingResultsDialog, ActivityLinkingDialog, ActivityLinkingResultsDialog, ProjectDeletionDialog, - ScenarioDatabaseDialog + ScenarioDatabaseDialog, LocationLinkingDialog ) from .line_edit import (SignalledPlainTextEdit, SignalledComboEdit, SignalledLineEdit) diff --git a/activity_browser/ui/widgets/dialog.py b/activity_browser/ui/widgets/dialog.py index 9b7c18e02..3d2a1835d 100644 --- a/activity_browser/ui/widgets/dialog.py +++ b/activity_browser/ui/widgets/dialog.py @@ -1145,3 +1145,72 @@ def construct_dialog(cls, parent: QtWidgets.QWidget = None, options: list = None obj.grid.addWidget(combo, i, 2, 1, 2) obj.updateGeometry() return obj + + +class LocationLinkingDialog(QtWidgets.QDialog): + """Display all of the possible location links in a single dialog for the user. + + Allow users to select alternate location links and an option to link to generic alternatives (GLO, RoW). + """ + def __init__(self, parent=None): + super().__init__(parent) + self.setWindowTitle("Activity Location linking") + + self.loc_label = QtWidgets.QLabel() + self.label_choices = [] + self.grid_box = QtWidgets.QGroupBox("Location link:") + self.grid = QtWidgets.QGridLayout() + self.grid_box.setLayout(self.grid) + + self.use_alternatives_checkbox = QtWidgets.QCheckBox('Use generic alternatives (GLO, RoW) as fallback') + self.use_alternatives_checkbox.setToolTip('If the location is not found, try to match to generic locations ' + 'like GLO and RoW.') + + self.buttons = QtWidgets.QDialogButtonBox( + QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, + ) + self.buttons.accepted.connect(self.accept) + self.buttons.rejected.connect(self.reject) + + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.loc_label) + layout.addWidget(self.grid_box) + layout.addWidget(self.use_alternatives_checkbox) + layout.addWidget(self.buttons) + self.setLayout(layout) + + @property + def relink(self) -> dict: + """Returns a dictionary of str -> str key/values, showing which keys + should be linked to which values. + + Only returns key/value pairs if they differ. + """ + return { + label.text(): combo.currentText() for label, combo in self.label_choices + if label.text() != combo.currentText() + } + + @classmethod + def construct_dialog(cls, label: str, options: List[Tuple[str, List[str]]], + parent: QtWidgets.QWidget = None) -> 'LocationLinkingDialog': + obj = cls(parent) + obj.loc_label.setText(label) + # Start at 1 because row 0 is taken up by the loc_label + for i, item in enumerate(options): + label = QtWidgets.QLabel(item[0]) + combo = QtWidgets.QComboBox() + combo.addItems(item[1]) + combo.setCurrentText(item[0]) + obj.label_choices.append((label, combo)) + obj.grid.addWidget(label, i, 0, 1, 2) + obj.grid.addWidget(combo, i, 2, 1, 2) + + obj.updateGeometry() + return obj + + @classmethod + def relink_location(cls, options: List[Tuple[str, List[str]]], + parent=None) -> 'LocationLinkingDialog': + label = "Relinking exchange locations from activity to a new location." + return cls.construct_dialog(label, options, parent) From 8d55c6cb8437d8f377aa2859f9d0cc2010145b35 Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Sat, 23 Sep 2023 23:08:14 +0200 Subject: [PATCH 30/32] Implement finding of suitable alternatives and proper management of failing that. --- activity_browser/controllers/activity.py | 81 ++++++++++++++++++------ activity_browser/ui/tables/inventory.py | 7 +- activity_browser/ui/widgets/dialog.py | 22 ++++--- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/activity_browser/controllers/activity.py b/activity_browser/controllers/activity.py index 33b88ae79..86c4cb1b7 100644 --- a/activity_browser/controllers/activity.py +++ b/activity_browser/controllers/activity.py @@ -147,43 +147,86 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: This function will try and link all exchanges in the same location as the production process to a chosen location, if none is available for the given exchange, it will try to link to RoW and then GLO, if those don't exist, the exchange is not altered. + + This def does the following: + - Read all databases in exchanges of activity into MetaDataStore + - Give user dialog to re-link location and potentially use alternatives + - Finds suitable activities with new location (and potentially alternative) + - Re-link exchanges to new (and potentially alternative) location + - Show user what changes are.??? """ #TODO actually write def, this is just a copy of duplicate_activity above - #TODO write such that it takes only one activity as input - activities = self._retrieve_activities(data) + act = self._retrieve_activities(data)[0] # get list of dependent databases for activity and load to MetaDataStore databases = [] - - for act in activities: - for exch in act.technosphere(): - databases.append(exch['input'][0]) + for exch in act.technosphere(): + databases.append(exch['input'][0]) # load all dependent databases to MetaDataStore - dbs = [AB_metadata.get_database_metadata(db) for db in databases] + dbs = {db: AB_metadata.get_database_metadata(db) for db in databases} # get list of all unique locations in the dependent databases (sorted alphabetically) locations = [] - for db in dbs: + for db in dbs.values(): locations += db['location'].to_list() # add all locations to one list locations = list(set(locations)) # reduce the list to only unique items locations.sort() # get the location to relink - db = AB_metadata.get_database_metadata(act.key[0]) - old_location = db.loc[db['key'] == act.key]['location'][0] + db = dbs[act.key[0]] + old_location = db.loc[db['key'] == act.key]['location'].iloc[0] # trigger dialog with autocomplete-writeable-dropdown-list options = (old_location, locations) - dialog = LocationLinkingDialog.relink_location(options, self.window) - relinking_results = dict() - if dialog.exec_() == LocationLinkingDialog.Accepted: - for old, new in dialog.relink.items(): - relinking_results[old] = new - use_alternatives = dialog.use_alternatives_checkbox.isChecked() + dialog = LocationLinkingDialog.relink_location(act['name'], options, self.window) + if dialog.exec_() != LocationLinkingDialog.Accepted: + # if the dialog accept button is not clicked, do nothing + return + + # read the data from the dialog + for old, new in dialog.relink.items(): + new_location = new + use_alternatives = dialog.use_alternatives_checkbox.isChecked() + + succesful_links = {} # key: old key, value: new key + alternatives = ['RoW', 'GLO'] # alternatives to try to match to + # get exchanges to re-link + for exch in act.technosphere(): + db = dbs[exch['input'][0]] + if db.loc[db['key'] == exch['input']]['location'].iloc[0] != old_location: + continue # this exchange has a location we're not trying to re-link, continue + + # get relevant data to match on + row = db.loc[db['key'] == exch['input']] + name = row['name'].iloc[0] + prod = row['reference product'].iloc[0] + unit = row['unit'].iloc[0] + + # get candidates to match + candidates = db.loc[(db['name'] == name) + & (db['reference product'] == prod) + & (db['unit'] == unit)] + if len(candidates) <= 1: + continue # this activity does not exist in this database with another location (1 is self), continue + + # check candidates for new_location + candidate = candidates.loc[candidates['location'] == new_location] + if len(candidate) == 0 and not use_alternatives: + continue # there is no candidate, continue + elif len(candidate) > 1: + continue # there is more than one candidate, we can't know what to use, continue + elif len(candidate) == 0: + # there are no candidates, but we can try alternatives + for alt in alternatives: + candidate = candidates.loc[candidates['location'] == alt] + if len(candidate) != 0: + break # found an alternative in with this alternative location, stop looking + + # at this point, we have found 1 suitable candidate, whether that is new_location or alternative location + succesful_links[exch['input']] = candidate['key'].iloc[0] + + # now, create a new activity and do the actual re-linking - # check every exchange (act.technosphere) whether it can be replaced - # write a def that tries to find the processes and potential alternatives - # use MetaDataStore to quickly find things # for act in activities: # new_code = self.generate_copy_code(act.key) diff --git a/activity_browser/ui/tables/inventory.py b/activity_browser/ui/tables/inventory.py index 19a1b9907..60c8998d2 100644 --- a/activity_browser/ui/tables/inventory.py +++ b/activity_browser/ui/tables/inventory.py @@ -118,7 +118,7 @@ def __init__(self, parent=None): ) self.duplicate_activity_new_loc_action.setToolTip( "Duplicate this activity to another location.\n" - "Link the exchanges to a new location if it is availabe.") + "Link the exchanges to a new location if it is availabe.") # only for 1 activity self.delete_activity_action = QtWidgets.QAction( qicons.delete, "Delete activity/-ies", None ) @@ -143,8 +143,11 @@ def contextMenuEvent(self, event) -> None: if len(self.selectedIndexes()) > 1: act = 'activities' + self.duplicate_activity_new_loc_action.setEnabled(False) else: act = 'activity' + self.duplicate_activity_new_loc_action.setEnabled(True) + self.duplicate_activity_action.setText("Duplicate {}".format(act)) self.delete_activity_action.setText("Delete {}".format(act)) @@ -165,8 +168,6 @@ def contextMenuEvent(self, event) -> None: menu.addAction(self.new_activity_action) menu.addAction(self.duplicate_activity_action) menu.addAction(self.duplicate_activity_new_loc_action) - if len(self.selectedIndexes()) > 1: - self.duplicate_activity_new_loc_action.setEnabled(False) menu.addAction(self.delete_activity_action) menu.addAction( qicons.edit, "Relink the activity exchanges", diff --git a/activity_browser/ui/widgets/dialog.py b/activity_browser/ui/widgets/dialog.py index 3d2a1835d..a73848c64 100644 --- a/activity_browser/ui/widgets/dialog.py +++ b/activity_browser/ui/widgets/dialog.py @@ -1194,23 +1194,25 @@ def relink(self) -> dict: @classmethod def construct_dialog(cls, label: str, options: List[Tuple[str, List[str]]], parent: QtWidgets.QWidget = None) -> 'LocationLinkingDialog': + loc, locs = options + obj = cls(parent) obj.loc_label.setText(label) + + label = QtWidgets.QLabel(loc) + combo = QtWidgets.QComboBox() + combo.addItems(locs) + combo.setCurrentText(loc) + obj.label_choices.append((label, combo)) # Start at 1 because row 0 is taken up by the loc_label - for i, item in enumerate(options): - label = QtWidgets.QLabel(item[0]) - combo = QtWidgets.QComboBox() - combo.addItems(item[1]) - combo.setCurrentText(item[0]) - obj.label_choices.append((label, combo)) - obj.grid.addWidget(label, i, 0, 1, 2) - obj.grid.addWidget(combo, i, 2, 1, 2) + obj.grid.addWidget(label, 0, 0, 1, 2) + obj.grid.addWidget(combo, 0, 2, 1, 2) obj.updateGeometry() return obj @classmethod - def relink_location(cls, options: List[Tuple[str, List[str]]], + def relink_location(cls, act_name: str, options: List[Tuple[str, List[str]]], parent=None) -> 'LocationLinkingDialog': - label = "Relinking exchange locations from activity to a new location." + label = "Relinking exchanges from activity '{}' to a new location.".format(act_name) return cls.construct_dialog(label, options, parent) From ef46b87415411b7513c4116b75bfb7bf4f72fd86 Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Mon, 25 Sep 2023 20:49:43 +0200 Subject: [PATCH 31/32] Implement actual relinking --- activity_browser/controllers/activity.py | 109 +++++++++++++++------- activity_browser/layouts/tabs/activity.py | 1 + activity_browser/signals.py | 1 + activity_browser/ui/widgets/activity.py | 2 +- activity_browser/ui/widgets/dialog.py | 4 +- 5 files changed, 81 insertions(+), 36 deletions(-) diff --git a/activity_browser/controllers/activity.py b/activity_browser/controllers/activity.py index 86c4cb1b7..943b9a9d7 100644 --- a/activity_browser/controllers/activity.py +++ b/activity_browser/controllers/activity.py @@ -155,13 +155,12 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: - Re-link exchanges to new (and potentially alternative) location - Show user what changes are.??? """ - #TODO actually write def, this is just a copy of duplicate_activity above - act = self._retrieve_activities(data)[0] + act = self._retrieve_activities(data)[0] # we only take one activity but this function always returns list # get list of dependent databases for activity and load to MetaDataStore databases = [] for exch in act.technosphere(): - databases.append(exch['input'][0]) + databases.append(exch.input[0]) # load all dependent databases to MetaDataStore dbs = {db: AB_metadata.get_database_metadata(db) for db in databases} @@ -188,16 +187,18 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: new_location = new use_alternatives = dialog.use_alternatives_checkbox.isChecked() - succesful_links = {} # key: old key, value: new key + keep_exch = [] # keep these exchanges + succesful_links = {} # dict of dicts, key of new exch : {new values} <-- see 'values' below alternatives = ['RoW', 'GLO'] # alternatives to try to match to # get exchanges to re-link for exch in act.technosphere(): - db = dbs[exch['input'][0]] - if db.loc[db['key'] == exch['input']]['location'].iloc[0] != old_location: + db = dbs[exch.input[0]] + if db.loc[db['key'] == exch.input]['location'].iloc[0] != old_location: + keep_exch.append(exch.input) continue # this exchange has a location we're not trying to re-link, continue # get relevant data to match on - row = db.loc[db['key'] == exch['input']] + row = db.loc[db['key'] == exch.input] name = row['name'].iloc[0] prod = row['reference product'].iloc[0] unit = row['unit'].iloc[0] @@ -207,47 +208,68 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: & (db['reference product'] == prod) & (db['unit'] == unit)] if len(candidates) <= 1: + keep_exch.append(exch.input) continue # this activity does not exist in this database with another location (1 is self), continue # check candidates for new_location candidate = candidates.loc[candidates['location'] == new_location] if len(candidate) == 0 and not use_alternatives: + keep_exch.append(exch.input) continue # there is no candidate, continue elif len(candidate) > 1: + keep_exch.append(exch.input) continue # there is more than one candidate, we can't know what to use, continue elif len(candidate) == 0: # there are no candidates, but we can try alternatives + no_alt = True for alt in alternatives: candidate = candidates.loc[candidates['location'] == alt] if len(candidate) != 0: + no_alt = False break # found an alternative in with this alternative location, stop looking + if no_alt: + # no alternative found, despite alternatives + keep_exch.append(exch.input) # at this point, we have found 1 suitable candidate, whether that is new_location or alternative location - succesful_links[exch['input']] = candidate['key'].iloc[0] - - # now, create a new activity and do the actual re-linking - - - # for act in activities: - # new_code = self.generate_copy_code(act.key) - # new_act = act.copy(new_code) - # # Update production exchanges - # for exc in new_act.production(): - # if exc.input.key == act.key: - # exc.input = new_act - # exc.save() - # # Update 'products' - # for product in new_act.get('products', []): - # if product.get('input') == act.key: - # product['input'] = new_act.key - # new_act.save() - # AB_metadata.update_metadata(new_act.key) - # signals.safe_open_activity_tab.emit(new_act.key) - # - # db = next(iter(activities)).get("database") - # bw.databases.set_modified(db) - # signals.database_changed.emit(db) - # signals.databases_changed.emit() + values = { + 'amount': exch.get('amount', False), + 'comment': exch.get('comment', False), + 'formula': exch.get('formula', False), + 'uncertainty': exch.get('uncertainty', False) + } + succesful_links[candidate['key'].iloc[0]] = values + + # now, create a new activity by copying the old one + db_name = act.key[0] + new_code = self.generate_copy_code(act.key) + new_act = act.copy(new_code) + # update production exchanges + for exc in new_act.production(): + if exc.input.key == act.key: + exc.input = new_act + exc.save() + # update 'products' + for product in new_act.get('products', []): + if product.get('input') == act.key: + product.input = new_act.key + new_act.save() + # save the new location to the activity + self.modify_activity(new_act.key, 'location', new_location) + # delete old exchanges + delete_exch = [exch for exch in new_act.technosphere() if exch.input not in keep_exch] + signals.exchanges_deleted.emit(delete_exch) + # add the new exchanges with all values carried over from last exch + signals.exchanges_add_w_values.emit(list(succesful_links.keys()), new_act.key, succesful_links) + + # update the MetaDataStore and open new activity + AB_metadata.update_metadata(new_act.key) + signals.safe_open_activity_tab.emit(new_act.key) + + # send signals to relevant locations + bw.databases.set_modified(db_name) + signals.database_changed.emit(db_name) + signals.databases_changed.emit() @Slot(tuple, str, name="copyActivityToDbInterface") @Slot(list, str, name="copyActivitiesToDbInterface") @@ -348,13 +370,29 @@ def __init__(self, parent=None): signals.exchanges_deleted.connect(self.delete_exchanges) signals.exchanges_add.connect(self.add_exchanges) + signals.exchanges_add_w_values.connect(self.add_exchanges) signals.exchange_modified.connect(self.modify_exchange) signals.exchange_uncertainty_wizard.connect(self.edit_exchange_uncertainty) signals.exchange_uncertainty_modified.connect(self.modify_exchange_uncertainty) signals.exchange_pedigree_modified.connect(self.modify_exchange_pedigree) @Slot(list, tuple, name="addExchangesToKey") - def add_exchanges(self, from_keys: Iterator[tuple], to_key: tuple) -> None: + def add_exchanges(self, from_keys: Iterator[tuple], to_key: tuple, new_values: dict = {}) -> None: + """ + Add new exchanges. + + Optionally add new values also. + + Parameters + ---------- + from_keys: The activities (keys) to create exchanges from + to_key: The activity (key) to create an exchange to + new_values: Values of the exchange, dict (from_keys as keys) with field names and values for the exchange + + Returns + ------- + + """ activity = bw.get_activity(to_key) for key in from_keys: technosphere_db = bc.is_technosphere_db(key[0]) @@ -365,6 +403,11 @@ def add_exchanges(self, from_keys: Iterator[tuple], to_key: tuple) -> None: exc['type'] = 'biosphere' else: exc['type'] = 'unknown' + # add optional exchange values + if new_vals := new_values.get(key, {}): + for field_name, value in new_vals.items(): + if value: + exc[field_name] = value exc.save() bw.databases.set_modified(to_key[0]) AB_metadata.update_metadata(to_key) diff --git a/activity_browser/layouts/tabs/activity.py b/activity_browser/layouts/tabs/activity.py index 40875b3f6..76ec878e1 100644 --- a/activity_browser/layouts/tabs/activity.py +++ b/activity_browser/layouts/tabs/activity.py @@ -157,6 +157,7 @@ def __init__(self, key: tuple, parent=None, read_only=True): self.grouped_tables = [DetailsGroupBox(l, t) for l, t in self.exchange_tables] # activity-specific data displayed and editable near the top of the tab + # this contains: activity name, location, database self.activity_data_grid = ActivityDataGrid(read_only=self.read_only, parent=self) self.db_read_only_changed(db_name=self.db_name, db_read_only=self.db_read_only) diff --git a/activity_browser/signals.py b/activity_browser/signals.py index 5eb4a15ab..a949a950f 100644 --- a/activity_browser/signals.py +++ b/activity_browser/signals.py @@ -65,6 +65,7 @@ class Signals(QObject): # Exchanges exchanges_deleted = Signal(list) # These exchanges should be deleted | list of exchange keys exchanges_add = Signal(list, tuple) # Add these exchanges to this activity | list of exchange keys to be added, key of target activity + exchanges_add_w_values = Signal(list, tuple, dict) # Add these exchanges to this activity with these values| list of exchange keys to be added, key of target activity, values to add per exchange exchange_modified = Signal(object, str, object) # This was changed about this exchange | exchange object, name of the changed field, new content of the field # Exchange object and uncertainty dictionary exchange_uncertainty_wizard = Signal(object) # Trigger uncertainty dialog for this exchange | exchange object diff --git a/activity_browser/ui/widgets/activity.py b/activity_browser/ui/widgets/activity.py index c88fcc3e1..75fdd1367 100644 --- a/activity_browser/ui/widgets/activity.py +++ b/activity_browser/ui/widgets/activity.py @@ -160,7 +160,7 @@ def duplicate_confirm_dialog(self, target_db): """ Get user confirmation for duplication action """ title = "Duplicate activity to new database" text = "Copy {} to {} and open as new tab?".format( - self.parent.activity.get('name', 'Error: Name of Act not found'), target_db) + self.parent.activity.get('name', 'Error: Name of activity not found'), target_db) user_choice = QMessageBox.question(self, title, text, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if user_choice == QMessageBox.Yes: diff --git a/activity_browser/ui/widgets/dialog.py b/activity_browser/ui/widgets/dialog.py index a73848c64..0cb1565da 100644 --- a/activity_browser/ui/widgets/dialog.py +++ b/activity_browser/ui/widgets/dialog.py @@ -1162,9 +1162,9 @@ def __init__(self, parent=None): self.grid = QtWidgets.QGridLayout() self.grid_box.setLayout(self.grid) - self.use_alternatives_checkbox = QtWidgets.QCheckBox('Use generic alternatives (GLO, RoW) as fallback') + self.use_alternatives_checkbox = QtWidgets.QCheckBox('Use generic alternatives (RoW, GLO) as fallback') self.use_alternatives_checkbox.setToolTip('If the location is not found, try to match to generic locations ' - 'like GLO and RoW.') + 'RoW or GLO (in that order).') self.buttons = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, From 58c7ad7ec52388bdd5329cfb7913eff0649e6ec4 Mon Sep 17 00:00:00 2001 From: marc-vdm Date: Tue, 26 Sep 2023 11:32:01 +0200 Subject: [PATCH 32/32] Minor documentation improvements + store exchanges to remove instead of to keep. --- activity_browser/controllers/activity.py | 34 +++++++++++++----------- activity_browser/signals.py | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/activity_browser/controllers/activity.py b/activity_browser/controllers/activity.py index 943b9a9d7..abb2bd036 100644 --- a/activity_browser/controllers/activity.py +++ b/activity_browser/controllers/activity.py @@ -141,7 +141,7 @@ def duplicate_activity(self, data: Union[tuple, Iterator[tuple]]) -> None: signals.databases_changed.emit() @Slot(tuple, name="copyActivityNewLoc") - def duplicate_activity_new_loc(self, data: tuple) -> None: + def duplicate_activity_new_loc(self, old_key: tuple) -> None: """Duplicates the selected activity in the same db, links to new location, with a new BW code. This function will try and link all exchanges in the same location as the production process @@ -153,9 +153,15 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: - Give user dialog to re-link location and potentially use alternatives - Finds suitable activities with new location (and potentially alternative) - Re-link exchanges to new (and potentially alternative) location - - Show user what changes are.??? + + Parameters + ---------- + old_key: the key of the activity to re-link to a different location + + Returns + ------- """ - act = self._retrieve_activities(data)[0] # we only take one activity but this function always returns list + act = self._retrieve_activities(old_key)[0] # we only take one activity but this function always returns list # get list of dependent databases for activity and load to MetaDataStore databases = [] @@ -187,14 +193,18 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: new_location = new use_alternatives = dialog.use_alternatives_checkbox.isChecked() - keep_exch = [] # keep these exchanges + del_exch = [] # delete these exchanges succesful_links = {} # dict of dicts, key of new exch : {new values} <-- see 'values' below alternatives = ['RoW', 'GLO'] # alternatives to try to match to + # in the future, 'alternatives' could be improved by making use of some location hierarchy. From that we could + # get things like if the new location is NL but there is no NL, but RER exists, we use that. However, for that + # we need some hierarchical structure to the location data, which may be available from ecoinvent, but we need + # to look for that. + # get exchanges to re-link for exch in act.technosphere(): db = dbs[exch.input[0]] if db.loc[db['key'] == exch.input]['location'].iloc[0] != old_location: - keep_exch.append(exch.input) continue # this exchange has a location we're not trying to re-link, continue # get relevant data to match on @@ -203,35 +213,28 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: prod = row['reference product'].iloc[0] unit = row['unit'].iloc[0] - # get candidates to match + # get candidates to match (must have same name, product and unit) candidates = db.loc[(db['name'] == name) & (db['reference product'] == prod) & (db['unit'] == unit)] if len(candidates) <= 1: - keep_exch.append(exch.input) continue # this activity does not exist in this database with another location (1 is self), continue # check candidates for new_location candidate = candidates.loc[candidates['location'] == new_location] if len(candidate) == 0 and not use_alternatives: - keep_exch.append(exch.input) continue # there is no candidate, continue elif len(candidate) > 1: - keep_exch.append(exch.input) continue # there is more than one candidate, we can't know what to use, continue elif len(candidate) == 0: # there are no candidates, but we can try alternatives - no_alt = True for alt in alternatives: candidate = candidates.loc[candidates['location'] == alt] if len(candidate) != 0: - no_alt = False break # found an alternative in with this alternative location, stop looking - if no_alt: - # no alternative found, despite alternatives - keep_exch.append(exch.input) # at this point, we have found 1 suitable candidate, whether that is new_location or alternative location + del_exch.append(exch) values = { 'amount': exch.get('amount', False), 'comment': exch.get('comment', False), @@ -257,8 +260,7 @@ def duplicate_activity_new_loc(self, data: tuple) -> None: # save the new location to the activity self.modify_activity(new_act.key, 'location', new_location) # delete old exchanges - delete_exch = [exch for exch in new_act.technosphere() if exch.input not in keep_exch] - signals.exchanges_deleted.emit(delete_exch) + signals.exchanges_deleted.emit(del_exch) # add the new exchanges with all values carried over from last exch signals.exchanges_add_w_values.emit(list(succesful_links.keys()), new_act.key, succesful_links) diff --git a/activity_browser/signals.py b/activity_browser/signals.py index a949a950f..db0454e75 100644 --- a/activity_browser/signals.py +++ b/activity_browser/signals.py @@ -44,7 +44,7 @@ class Signals(QObject): new_activity = Signal(str) # Trigger dialog to create a new activity in this database | name of database add_activity_to_history = Signal(tuple) # Add this activity to history | key of activity duplicate_activity = Signal(tuple) # Duplicate this activity | key of activity - duplicate_activity_new_loc = Signal(tuple) # Duplicate this activity to a new location | key of activity + duplicate_activity_new_loc = Signal(tuple) # Trigger dialog to duplicate this activity to a new location | key of activity duplicate_activities = Signal(list) # Duplicate these activities | list of activity keys duplicate_activity_to_db = Signal(str, object) # Duplicate this activity to another database | name of target database, BW2 actiivty object #TODO write below 2 signals to work without the str, source database is already stored in activity keys