Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better biosphere install/update handling #1145

Merged
merged 101 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 99 commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
855ce5f
Delete .github/workflows/install-canary.yaml
marc-vdm Sep 26, 2023
e07a4ea
Add testing file
marc-vdm Nov 29, 2023
6065ace
Get available AB versions per AB version from online file
marc-vdm Nov 29, 2023
63a22f1
Limit ecoinvent importer to versions compatible with this AB version
marc-vdm Nov 30, 2023
625533f
Implement choosing of version during biosphere update
marc-vdm Nov 30, 2023
0d89b12
Implement choosing of version during defaults import
marc-vdm Nov 30, 2023
d892530
Resolve offline bug + better updating
marc-vdm Nov 30, 2023
c64d47e
move compatible versions file
marc-vdm Nov 30, 2023
586cece
implement local file fallback
marc-vdm Nov 30, 2023
97b1a62
implement legacy biosphere imports for any chosen version AB is compa…
marc-vdm Dec 2, 2023
61eef97
update test
marc-vdm Dec 2, 2023
0321d0c
update test
marc-vdm Dec 2, 2023
82f2115
update test
marc-vdm Dec 2, 2023
78856a9
update test
marc-vdm Dec 2, 2023
e276052
update test
marc-vdm Dec 2, 2023
63c8248
update test
marc-vdm Dec 3, 2023
e5e6473
resolve calculation setup bug where activites are checked when biosph…
marc-vdm Dec 3, 2023
b788894
minor updates to test documentation
marc-vdm Dec 3, 2023
7999944
GH action script for commenting on issues when related milestone is c…
marc-vdm Dec 4, 2023
9699278
update bw2io requirement
marc-vdm Sep 17, 2023
69f0a4e
Update readme install instructions
marc-vdm Sep 17, 2023
a7fbd60
Update meta.yaml
marc-vdm Sep 17, 2023
c8fe954
Update README.md
marc-vdm Sep 17, 2023
5cb49c7
Change requirement to brightway2 instead of bw2io
marc-vdm Sep 18, 2023
7da0e5c
Update README.md
bsteubing Sep 25, 2023
a76fd33
Increases the flexibility of the excel importer so it can also handle…
Zoophobus Sep 22, 2023
306d2ff
Update README.md
bsteubing Sep 27, 2023
b2f30cf
Set up signals infrascructure
marc-vdm Sep 22, 2023
7cd8c59
Implement dialog
marc-vdm Sep 23, 2023
8ed34c8
Implement finding of suitable alternatives and proper management of f…
marc-vdm Sep 23, 2023
c666159
Implement actual relinking
marc-vdm Sep 25, 2023
5e97cfa
Minor documentation improvements + store exchanges to remove instead …
marc-vdm Sep 26, 2023
c3972b2
Minor documentation + code improvements
marc-vdm Sep 22, 2023
21b8d8d
Resolve #782 + improve documentation of `Contributions` class
marc-vdm Sep 28, 2023
3ad0ba8
Minor documentation + code improvements
marc-vdm Sep 22, 2023
752bd13
Fix type hinting error
marc-vdm Sep 28, 2023
97ad641
Update README.md
marc-vdm Oct 11, 2023
8854cb6
Update README.md
marc-vdm Oct 11, 2023
1e5fe27
Update README.md
marc-vdm Oct 11, 2023
3852c71
Updates to the functions get_relevant_flows and get_relevant_activiti…
Zoophobus Oct 14, 2023
b6e9c41
Multiple sdf update (#1083)
Zoophobus Oct 20, 2023
92aa40f
Use node16 actions for main pipeline
haasad Oct 29, 2023
909408b
Use node16 actions in release pipeline
haasad Oct 29, 2023
0654b82
Use latest version of release-changelog-builder
haasad Oct 29, 2023
e564225
Use node16 action for install canary pipeline
haasad Oct 29, 2023
ab19c06
Remove the special build for arm architecture
haasad Oct 29, 2023
9addfb8
Install canary updates (#1093)
haasad Oct 30, 2023
2165bb6
Adding error message if no scenario file is loaded in a scenario LCA …
bsteubing Nov 2, 2023
3f1638c
Updated and improved contributing file
marc-vdm Oct 21, 2023
b6879f2
Improve text on dependencies
marc-vdm Oct 21, 2023
fa8ace6
Fix canary link
marc-vdm Oct 21, 2023
4fc7b3b
Add good/bad examples to CONTRIBUTING.md for commit messages and PR t…
marc-vdm Oct 21, 2023
ebf897d
Add more specific requirements on communicating work on issues in CON…
marc-vdm Oct 21, 2023
49b1888
Minor updates to CONTRIBUTING.md and README.md
marc-vdm Oct 23, 2023
2439f55
Minor improvements to CONTRIBUTING.md
marc-vdm Oct 24, 2023
87ab077
Fix formatting error in PULL_REQUEST_TEMPLATE.md
marc-vdm Nov 7, 2023
3480eb5
Resolve #1105
marc-vdm Nov 7, 2023
237b830
Update copyright and license information to only link to one place.
marc-vdm Nov 7, 2023
1d0283a
Resolve 3 bugs for location linking (#1051): 1) database of own activ…
marc-vdm Nov 7, 2023
2b5c713
Improve choosing and handling of alternative locations for location c…
marc-vdm Nov 7, 2023
f9973f2
Resolve readonly database bug for activity duplication to new activity.
marc-vdm Nov 8, 2023
de043cb
Store AB version in logfile
marc-vdm Nov 9, 2023
591c407
Remove deprecated channels from conda envs
haasad Nov 10, 2023
4c0b0d3
Remove experimental conda environment creation and upload
haasad Nov 10, 2023
a377fce
Move conda-envs to .github directory
haasad Nov 10, 2023
8f9f4f7
Move changelog config to .github
haasad Nov 10, 2023
2ffcacd
Move dev recipe to .github directory
haasad Nov 10, 2023
34e0ffa
Move stable recipe to recipe/meta.yaml
haasad Nov 10, 2023
8b5ae43
Update dev recipe
haasad Nov 10, 2023
41c1b27
Use micromamba instead of miniconda to speed up tests
haasad Nov 10, 2023
1c36207
Update install instructions to use libmamba solver with conda
haasad Nov 11, 2023
fb8faac
Fix path for dev recipe
haasad Nov 13, 2023
0a09c46
Added tooltip for table content
mrvisscher Nov 16, 2023
8f6796b
Added docstring for data method
mrvisscher Nov 16, 2023
cd9c891
Cleaning-up documentation
mrvisscher Nov 17, 2023
504a6d8
Update README.md
marc-vdm Nov 22, 2023
94b3295
Add - copy on impact category copy (#1136)
mrvisscher Nov 24, 2023
bd8f748
Resolve bug with switching project on delete (#1138)
mrvisscher Nov 28, 2023
8bf5f8d
Merge branch 'master' of https://github.com/LCA-ActivityBrowser/activ…
marc-vdm Dec 4, 2023
a5628e4
Merge pull request #9 from marc-vdm/auto_point_to_new_release
marc-vdm Dec 4, 2023
6542568
GH action script for commenting on issues when related milestone is c…
marc-vdm Dec 4, 2023
f2afaeb
Merge pull request #10 from marc-vdm/gh_actions
marc-vdm Dec 4, 2023
a836d7c
GH action script for commenting on issues when related milestone is c…
marc-vdm Dec 4, 2023
ab7d30b
Merge pull request #11 from marc-vdm/gh_action2
marc-vdm Dec 4, 2023
96fe93c
GH action script for commenting on issues when related milestone is c…
marc-vdm Dec 4, 2023
5459404
Merge pull request #12 from marc-vdm/gh_action_for_closing_milestones
marc-vdm Dec 4, 2023
c1abfc7
Add test for semantic version sort
marc-vdm Dec 6, 2023
400c2d4
review instructions bot
marc-vdm Dec 6, 2023
21e03fb
Merge pull request #14 from marc-vdm/review_message
marc-vdm Dec 6, 2023
3ce5801
review instructions bot
marc-vdm Dec 6, 2023
8b8b041
Merge pull request #16 from marc-vdm/review_message2
marc-vdm Dec 6, 2023
c833778
Merge branch 'master' of https://github.com/LCA-ActivityBrowser/activ…
marc-vdm Dec 6, 2023
ea7cb81
Merge branch 'master' of https://github.com/marc-vdm/activity-browser
marc-vdm Dec 6, 2023
9c1242d
Merge branch 'master' of https://github.com/LCA-ActivityBrowser/activ…
marc-vdm Dec 13, 2023
c128d76
Merge branch 'master' into better_biosphere_handling
marc-vdm Dec 13, 2023
01c6c12
Update dialog text
marc-vdm Dec 13, 2023
8a9c71f
Passed main windows as parent to popup
mrvisscher Dec 13, 2023
8562d82
Update safe_link_fetch from utils
marc-vdm Dec 13, 2023
2d521ec
Merge branch 'better_biosphere_handling' of https://github.com/marc-v…
marc-vdm Dec 13, 2023
a00b626
Update safe_link_fetch from utils and update link to correct repo
marc-vdm Dec 13, 2023
a03cb71
Update safe_link_fetch from utils and update link to correct repo
marc-vdm Dec 13, 2023
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
35 changes: 35 additions & 0 deletions .github/workflows/comment-milestoned-issues.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: comment when milestone is closed
on:
milestone:
types: [closed]

jobs:
comment:
runs-on: ubuntu-latest
steps:
- name: Comment on issue
uses: actions/github-script@v5
with:
script: |
const milestone_number = context.payload.milestone.number;
const milestone_title = context.payload.milestone.title;

// Get all issues associated with the milestone
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
milestone: milestone_number,
state: 'all',
});

// Loop through the issues and if the issue was closed, post a comment referring to the new release
for (const issue of issues.data) {
if (issue.state === 'closed') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `This issue has been implemented in the [new release of Activity Browser 🚀 (version ${milestone_title})](https://github.com/LCA-ActivityBrowser/activity-browser/releases/tag/${milestone_title}), you can get the new version by [updating Activity Browser](https://github.com/LCA-ActivityBrowser/activity-browser#updating-the-ab).\n\n_🤖beep boop! I'm a bot and this message was an automated action. If updating does not make sense for this issue, just ignore this._`,
});
}
}
32 changes: 32 additions & 0 deletions .github/workflows/request-review-instructions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: notify reviewer
on:
pull_request:
types: [review_requested]

jobs:
comment:
runs-on: ubuntu-latest
steps:
- name: Comment on PR
uses: actions/github-script@v5
with:
script: |
const pr_number = context.payload.pull_request.number;
const reviewer = context.payload.review.user.login;

const fs = require('fs');
const path = require('path');

// Read CONTRIBUTING.md
const markdown = fs.readFileSync(path.join(process.env.GITHUB_WORKSPACE, '../tree/master/CONTRIBUTING.md'), 'utf8');

// Extract Reviewing guidelines
const section = markdown.split('### Reviewing pull-requests')[1].split('###')[0];

// Post a comment tagging the reviewer asking them to review following the guidelines
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr_number,
body: `> [!NOTE]\n> @${reviewer}, your review was requested for this Pull Request. Please review this PR following these guidelines:\n\n___\n${section}\n\n\n🤖 _beep boop! I'm a bot and this was an automated message._`,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
'2.9': ['3.4', '3.5', '3.6', '3.7', '3.7.1', '3.8', '3.9', '3.9.1'],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from bw2io.importers import Ecospold2BiosphereImporter
from bw2io.importers.ecospold2_biosphere import EMISSIONS_CATEGORIES
from bw2data.utils import recursive_str_to_unicode
from zipfile import ZipFile

from ...info import __ei_versions__
from ...utils import sort_semantic_versions

import os
from lxml import objectify

import logging
from activity_browser.logger import ABHandler

logger = logging.getLogger('ab_logs')
log = ABHandler.setup_with_logger(logger, __name__)

def create_default_biosphere3(version) -> None:
"""Reimplementation of bw.create_default_biosphere3 to allow import from older biosphere versions."""
# format version number to only Major/Minor
version = version[:3]

if version == sort_semantic_versions(__ei_versions__)[0]:
# most recent version
eb = Ecospold2BiosphereImporter()
else:
# not most recent version, import legacy biosphere from AB
eb = ABEcospold2BiosphereImporter(version=version)
eb.apply_strategies()
eb.write_database()


class ABEcospold2BiosphereImporter(Ecospold2BiosphereImporter):
"""Reimplementation of bw2io.importers Ecospold2BiosphereImporter to import legacy biosphere from AB data"""

def extract(self, version):
def extract_flow_data(o):
ds = {
"categories": (
o.compartment.compartment.text,
o.compartment.subcompartment.text,
),
"code": o.get("id"),
"CAS number": o.get("casNumber"),
"name": o.name.text,
"database": self.db_name,
"exchanges": [],
"unit": o.unitName.text,
}
ds["type"] = EMISSIONS_CATEGORIES.get(
ds["categories"][0], ds["categories"][0]
)
return ds

lci_dirpath = os.path.join(os.path.dirname(__file__), 'legacy_biosphere')

# find the most recent legacy biosphere that is equal to or older than chosen version
for ei_version in sort_semantic_versions(__ei_versions__):
use_version = ei_version
fp = os.path.join(lci_dirpath, f'ecoinvent elementary flows {use_version}.xml.zip')
if sort_semantic_versions([version, ei_version])[0] == version and os.path.isfile(fp):
# this version is equal/lower and available
break

# extract the xml from the zip
with ZipFile(fp) as zipped_file:
with zipped_file.open(f'ecoinvent elementary flows {use_version}.xml') as file:
root = objectify.parse(file).getroot()

log.debug(f'Installing biosphere {use_version} for chosen version {version}')
flow_data = recursive_str_to_unicode(
[extract_flow_data(ds) for ds in root.iterchildren()]
)

return flow_data
Binary file not shown.
Binary file not shown.
Binary file not shown.
36 changes: 29 additions & 7 deletions activity_browser/controllers/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
from ..bwutils.strategies import relink_exchanges_existing_db
from ..ui.widgets import (
CopyDatabaseDialog, DatabaseLinkingDialog, DefaultBiosphereDialog,
BiosphereUpdater, DatabaseLinkingResultsDialog
BiosphereUpdater, DatabaseLinkingResultsDialog, EcoinventVersionDialog
)
from ..ui.wizards.db_export_wizard import DatabaseExportWizard
from ..ui.wizards.db_import_wizard import DatabaseImportWizard
from ..settings import project_settings
from ..signals import signals
from .project import ProjectController
from ..info import __ei_versions__
from ..utils import sort_semantic_versions

import logging
from activity_browser.logger import ABHandler
Expand Down Expand Up @@ -66,23 +68,43 @@ def ensure_sqlite_indices(self):

@Slot(name="bw2Setup")
def install_default_data(self) -> None:
dialog = DefaultBiosphereDialog(self.window)

# let user choose version
version_dialog = EcoinventVersionDialog(self.window)
if version_dialog.exec_() != EcoinventVersionDialog.Accepted: return
version = version_dialog.options.currentText()

dialog = DefaultBiosphereDialog(version[:3], self.window) # only read Major/Minor part of version
dialog.show()

@Slot(name="updateBiosphereDialog")
def update_biosphere(self) -> None:
""" Open a popup with progression bar and run through the different
functions for adding ecoinvent biosphere flows.
"""
ok = QtWidgets.QMessageBox.question(
# warn user of consequences of updating
warn_dialog = QtWidgets.QMessageBox.question(
self.window, "Update biosphere3?",
"Updating the biosphere3 database cannot be undone!",
'Newer versions of the biosphere database may not\n'
'always be compatible with older ecoinvent versions.\n'
'\nUpdating the biosphere3 database cannot be undone!\n',
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Abort,
QtWidgets.QMessageBox.Abort
)
if ok == QtWidgets.QMessageBox.Ok:
dialog = BiosphereUpdater(self.window)
dialog.show()
if warn_dialog is not QtWidgets.QMessageBox.Ok: return

# let user choose version
version_dialog = EcoinventVersionDialog(self.window)
if version_dialog.exec_() != EcoinventVersionDialog.Accepted: return
version = version_dialog.options.currentText()

# reduce biosphere update list up to the selected version
sorted_versions = sort_semantic_versions(__ei_versions__, highest_to_lowest=False)
ei_versions = sorted_versions[:sorted_versions.index(version) + 1]

# show updating dialog
dialog = BiosphereUpdater(ei_versions, self.window)
dialog.show()

@Slot(name="addDatabase")
def add_database(self):
Expand Down
56 changes: 56 additions & 0 deletions activity_browser/info.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,62 @@
import ast
import os.path
from importlib.metadata import version, PackageNotFoundError
from .utils import safe_link_fetch, sort_semantic_versions

import logging
from .logger import ABHandler
logger = logging.getLogger('ab_logs')
log = ABHandler.setup_with_logger(logger, __name__)

# get AB version
try:
__version__ = version(__package__)
except PackageNotFoundError:
__version__ = "0.0.0"


def get_compatible_versions() -> list:
"""Get compatible versions of ecoinvent for this AB version.

Reads this file on github repo: activity-browser/better_biosphere_handling/compatible_ei_versions.txt'.
Converts file content to available ecoinvent versions for each version of AB.
Finds the correct available versions for this AB version, if failing to read version,
the lowest version in the file is chosen.
"""
try:
# read versions
versions_URL = 'https://raw.githubusercontent.com/marc-vdm/activity-browser/better_biosphere_handling/activity_browser/bwutils/ecoinvent_biosphere_versions/compatible_ei_versions.txt'
error, page = safe_link_fetch(versions_URL)
if not error:
file = page.text
else:
# silently try a local fallback:
log.debug(f'Reading online compatible ecoinvent versions failed '
f'-attempting local fallback- with this error: {error[:500]}')
file_path = os.path.join(os.path.dirname(__file__),
'bwutils',
'ecoinvent_biosphere_versions',
'compatible_ei_versions.txt')
with open(file_path, 'r') as f:
file = f.read()
all_versions = ast.literal_eval(file)

# select either the latest lower version available or if none available the lowest version for safety
sorted_versions = sort_semantic_versions(all_versions.keys())
for ab_version in sorted_versions:
if sort_semantic_versions([__version__, ab_version])[0] == __version__:
# current version is higher than or equal to tested AB version:
ei_versions = all_versions[ab_version]
break
else:
ei_versions = all_versions[sorted_versions[-1]]

log.debug(f'Following versions of ecoinvent are compatible with AB {__version__}: {ei_versions}')
return ei_versions

except Exception as error:
log.debug(f'Reading local fallback failed with: {error[:500]}')
return ['3.4', '3.5', '3.6', '3.7', '3.7.1', '3.8', '3.9', '3.9.1']


__ei_versions__ = get_compatible_versions()
1 change: 1 addition & 0 deletions activity_browser/ui/tables/models/lca_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def activities(self) -> list:
return [{x["key"]: x["Amount"]} for x in selection]

def check_activities(self, db):
if db == 'biosphere3': return # if biosphere changed, we don't need to check as it doesn't have activities.
databases = [list(k.keys())[0][0] for k in self.activities]
if db in databases:
self.sync()
Expand Down
2 changes: 1 addition & 1 deletion activity_browser/ui/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
DatabaseLinkingDialog, DefaultBiosphereDialog,
DatabaseLinkingResultsDialog, ActivityLinkingDialog,
ActivityLinkingResultsDialog, ProjectDeletionDialog,
ScenarioDatabaseDialog, LocationLinkingDialog
ScenarioDatabaseDialog, LocationLinkingDialog, EcoinventVersionDialog
)
from .line_edit import (SignalledPlainTextEdit, SignalledComboEdit,
SignalledLineEdit)
Expand Down
13 changes: 9 additions & 4 deletions activity_browser/ui/widgets/biosphere_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@


class BiosphereUpdater(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
def __init__(self, ei_versions, parent=None):
super().__init__(parent=parent)
self.setWindowTitle("Updating '{}' database".format(bw.config.biosphere))
self.setLabelText("Adding new flows to biosphere database")
self.setRange(0, 0)
self.show()

self.thread = UpdateBiosphereThread(self)
self.thread = UpdateBiosphereThread(ei_versions, self)
self.setMaximum(self.thread.total_patches)
self.thread.progress.connect(self.update_progress)
self.thread.finished.connect(self.finished)
Expand All @@ -43,16 +43,21 @@ def update_progress(self, current: int):
class UpdateBiosphereThread(QtCore.QThread):
PATCHES = [patch for patch in dir(data) if patch.startswith('add_ecoinvent') and patch.endswith('biosphere_flows')]
progress = Signal(int)
def __init__(self, parent=None):
def __init__(self, ei_versions, parent=None):
super().__init__(parent)

# reduce the patches list to only compatible versions for this AB version
self.PATCHES = [p for p in self.PATCHES if any(v.replace('.', '') in p for v in ei_versions)]

self.total_patches = len(self.PATCHES)

def run(self):
try:
for i, patch in enumerate(self.PATCHES):
self.progress.emit(i)
log.debug(f'Applying biosphere patch: {patch}')
update_bio = getattr(data, patch)
update_bio()
except ValidityError as e:
log.error("Could not patch biosphere: {}".format(str(e)))
log.error(f'Could not patch biosphere: {str(e)}')
self.exit(1)
Loading