bw-functional 0b95__tar.gz → 0b97__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bw_functional-0b95/bw_functional.egg-info → bw_functional-0b97}/PKG-INFO +3 -1
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/__init__.py +3 -7
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/allocation.py +4 -6
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/convert.py +4 -8
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/database.py +4 -6
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/edge_classes.py +13 -9
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/node_classes.py +11 -13
- {bw_functional-0b95 → bw_functional-0b97/bw_functional.egg-info}/PKG-INFO +3 -1
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional.egg-info/requires.txt +2 -0
- {bw_functional-0b95 → bw_functional-0b97}/pyproject.toml +2 -0
- {bw_functional-0b95 → bw_functional-0b97}/LICENSE +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/MANIFEST.in +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/README.md +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional/update.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional.egg-info/SOURCES.txt +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional.egg-info/dependency_links.txt +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/bw_functional.egg-info/top_level.txt +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/setup.cfg +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/setup.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/tests/test_allocation.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/tests/test_database.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/tests/test_mf_node.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/tests/test_process_node.py +0 -0
- {bw_functional-0b95 → bw_functional-0b97}/tests/test_product_node.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bw-functional
|
|
3
|
-
Version:
|
|
3
|
+
Version: 0b97
|
|
4
4
|
Summary: Code for handling multifunctional activities in Brightway
|
|
5
5
|
Author-email: Chris Mutel <cmutel@gmail.com>, Marin Visscher <m.r.visscher@cml.leidenuniv.nl>
|
|
6
6
|
Maintainer-email: Marin Visscher <m.r.visscher@cml.leidenuniv.nl>
|
|
@@ -23,6 +23,8 @@ Requires-Dist: blinker
|
|
|
23
23
|
Requires-Dist: bw2data>=4.0.1
|
|
24
24
|
Requires-Dist: bw2io>=0.9.1
|
|
25
25
|
Requires-Dist: bw_processing>=0.9.6
|
|
26
|
+
Requires-Dist: loguru
|
|
27
|
+
Requires-Dist: pandas
|
|
26
28
|
Provides-Extra: testing
|
|
27
29
|
Requires-Dist: bw-functional; extra == "testing"
|
|
28
30
|
Requires-Dist: bw2calc>=2.0.1; extra == "testing"
|
|
@@ -12,9 +12,7 @@ __all__ = (
|
|
|
12
12
|
"update",
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
from
|
|
16
|
-
# import os
|
|
17
|
-
from logging import getLogger
|
|
15
|
+
from loguru import logger
|
|
18
16
|
|
|
19
17
|
from bw2data import labels
|
|
20
18
|
from bw2data.subclass_mapping import DATABASE_BACKEND_MAPPING, NODE_PROCESS_CLASS_MAPPING
|
|
@@ -26,8 +24,6 @@ from .edge_classes import MFExchange, MFExchanges
|
|
|
26
24
|
from .convert import convert_sqlite_to_functional_sqlite, convert_functional_sqlite_to_sqlite
|
|
27
25
|
from .update import update, latest
|
|
28
26
|
|
|
29
|
-
log = getLogger(__name__)
|
|
30
|
-
|
|
31
27
|
DATABASE_BACKEND_MAPPING["functional_sqlite"] = FunctionalSQLiteDatabase
|
|
32
28
|
NODE_PROCESS_CLASS_MAPPING["functional_sqlite"] = FunctionalSQLiteDatabase.node_class
|
|
33
29
|
|
|
@@ -63,7 +59,7 @@ def _check_parameterized_exchange_for_allocation(_, name):
|
|
|
63
59
|
for key in process_keys:
|
|
64
60
|
process = bd.get_activity(key)
|
|
65
61
|
if not isinstance(process, Process):
|
|
66
|
-
|
|
62
|
+
logger.warning(f"Process {key} is not an instance of Process, skipping allocation check.")
|
|
67
63
|
continue
|
|
68
64
|
process.allocate()
|
|
69
65
|
|
|
@@ -75,7 +71,7 @@ def _check_and_update(dataset):
|
|
|
75
71
|
current = dataset.data.get("bw_functional_version")
|
|
76
72
|
|
|
77
73
|
if current != latest:
|
|
78
|
-
|
|
74
|
+
logger.info(f"Updating {dataset.name} to latest bw_functional datastructure version {latest}")
|
|
79
75
|
dataset.data["bw_functional_version"] = update(current)
|
|
80
76
|
dataset.save()
|
|
81
77
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
from functools import partial
|
|
2
|
-
from typing import Callable
|
|
3
|
-
from
|
|
2
|
+
from typing import Callable
|
|
3
|
+
from loguru import logger
|
|
4
4
|
|
|
5
5
|
from .node_classes import Process, Product
|
|
6
6
|
|
|
7
|
-
log = getLogger(__name__)
|
|
8
|
-
|
|
9
7
|
|
|
10
8
|
def generic_allocation(
|
|
11
9
|
process: Process,
|
|
@@ -49,7 +47,7 @@ def generic_allocation(
|
|
|
49
47
|
products.append(product)
|
|
50
48
|
|
|
51
49
|
if not products:
|
|
52
|
-
|
|
50
|
+
logger.warning(f"No products to allocate in process {process}")
|
|
53
51
|
return
|
|
54
52
|
|
|
55
53
|
# Calculate the total value for allocation
|
|
@@ -110,7 +108,7 @@ def get_property_value(
|
|
|
110
108
|
raise KeyError(f"Product {product} from {product.processor} missing property {property_label}")
|
|
111
109
|
|
|
112
110
|
if isinstance(prop, float):
|
|
113
|
-
|
|
111
|
+
logger.warning("Property using legacy float format")
|
|
114
112
|
return prop
|
|
115
113
|
|
|
116
114
|
if prop.get("normalize", False):
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import tqdm
|
|
2
|
-
from
|
|
3
|
-
|
|
2
|
+
from loguru import logger
|
|
4
3
|
import bw2data as bd
|
|
5
|
-
from bw2data.backends import SQLiteBackend
|
|
6
4
|
|
|
7
5
|
from .database import FunctionalSQLiteDatabase
|
|
8
6
|
|
|
9
|
-
log = getLogger(__name__)
|
|
10
|
-
|
|
11
7
|
|
|
12
8
|
def convert_sqlite_to_functional_sqlite(database_dict: dict) -> dict:
|
|
13
9
|
return SQLiteToFunctionalSQLite.convert(database_dict)
|
|
@@ -145,15 +141,15 @@ class FunctionalSQLiteToSQLite:
|
|
|
145
141
|
continue
|
|
146
142
|
|
|
147
143
|
if exc["type"] != "production" and ds.get("allocation_factor"):
|
|
148
|
-
|
|
144
|
+
logger.info(f"Allocating exchange from {exc['input']} to {ds['name']} "
|
|
149
145
|
f"with factor {ds['allocation_factor']}")
|
|
150
146
|
exc["amount"] = exc["amount"] * ds['allocation_factor']
|
|
151
147
|
if exc.get("formula"):
|
|
152
|
-
|
|
148
|
+
logger.info(f"Allocating formula from {exc['input']} to {ds['name']}: "
|
|
153
149
|
f"{exc['formula']} * {ds['allocation_factor']}")
|
|
154
150
|
exc["formula"] = f"{exc['formula']} * {ds['allocation_factor']}"
|
|
155
151
|
if exc.get("uncertainty type"):
|
|
156
|
-
|
|
152
|
+
logger.warning(f"Exchange from {exc['input']} to {ds['name']} has an uncertainty distribution that "
|
|
157
153
|
f"will not be allocated")
|
|
158
154
|
|
|
159
155
|
ds["exchanges"].append(exc)
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import sqlite3
|
|
2
2
|
import pickle
|
|
3
3
|
import datetime
|
|
4
|
-
from logging import getLogger
|
|
5
4
|
from time import time
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
import pandas as pd
|
|
6
|
+
from loguru import logger
|
|
9
7
|
from fsspec.implementations.zip import ZipFileSystem
|
|
10
8
|
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pandas as pd
|
|
11
11
|
import stats_arrays as sa
|
|
12
12
|
|
|
13
13
|
from bw_processing import clean_datapackage_name, create_datapackage
|
|
@@ -17,8 +17,6 @@ from pandas._libs.missing import NAType
|
|
|
17
17
|
|
|
18
18
|
from .node_classes import Process, Product
|
|
19
19
|
|
|
20
|
-
log = getLogger(__name__)
|
|
21
|
-
|
|
22
20
|
UNCERTAINTY_FIELDS = ["uncertainty_type", "loc", "scale", "shape", "minimum", "maximum"]
|
|
23
21
|
|
|
24
22
|
|
|
@@ -238,7 +236,7 @@ class FunctionalSQLiteDatabase(SQLiteBackend):
|
|
|
238
236
|
# Close the SQLite connection
|
|
239
237
|
con.close()
|
|
240
238
|
|
|
241
|
-
|
|
239
|
+
logger.debug(f"Processing: built tables from SQL in {time() - t:.2f} seconds")
|
|
242
240
|
|
|
243
241
|
return node_df, exc_df, dependents
|
|
244
242
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
from
|
|
1
|
+
from loguru import logger
|
|
2
2
|
from copy import deepcopy
|
|
3
3
|
|
|
4
|
-
from bw2data import projects, databases
|
|
4
|
+
from bw2data import projects, databases, errors
|
|
5
5
|
from bw2data.backends.proxies import Exchange, Exchanges, ExchangeDataset
|
|
6
6
|
|
|
7
|
-
log = getLogger(__name__)
|
|
8
|
-
|
|
9
7
|
|
|
10
8
|
class MFExchanges(Exchanges):
|
|
11
9
|
"""
|
|
@@ -106,7 +104,7 @@ class MFExchange(Exchange):
|
|
|
106
104
|
NotImplementedError: If parameterization is attempted for production exchanges.
|
|
107
105
|
"""
|
|
108
106
|
from .node_classes import Process, Product
|
|
109
|
-
|
|
107
|
+
logger.debug(f"Saving {self['type']} Exchange: {self}")
|
|
110
108
|
|
|
111
109
|
created = self.id is None # the exchange is new if it has no id
|
|
112
110
|
old = ExchangeDataset.get_by_id(self.id) if not created else None
|
|
@@ -145,12 +143,18 @@ class MFExchange(Exchange):
|
|
|
145
143
|
signal (bool, optional): Whether to send a signal after deletion. Defaults to True.
|
|
146
144
|
"""
|
|
147
145
|
from .node_classes import Product, Process, MFActivity
|
|
148
|
-
log.debug(f"Deleting {self['type']} Exchange: {self}")
|
|
149
146
|
|
|
150
|
-
|
|
147
|
+
try:
|
|
148
|
+
function = self.input
|
|
149
|
+
process = self.output
|
|
150
|
+
except errors.UnknownObject:
|
|
151
|
+
logger.warning(f"Could not retrieve input or output for exchange deletion. {self['input']=}, {self['output']=}")
|
|
152
|
+
super().delete(signal)
|
|
153
|
+
return
|
|
151
154
|
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
logger.debug(f"Deleting {self['type']} Exchange: {self}")
|
|
156
|
+
|
|
157
|
+
super().delete(signal)
|
|
154
158
|
|
|
155
159
|
if not isinstance(process, Process) or not isinstance(function, Product):
|
|
156
160
|
return
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
3
4
|
|
|
4
5
|
from bw2data import databases, get_node, labels
|
|
5
|
-
from bw2data.backends import ExchangeDataset
|
|
6
6
|
from bw2data.errors import UnknownObject, ValidityError
|
|
7
7
|
from bw2data.backends.proxies import Activity, ActivityDataset
|
|
8
8
|
|
|
9
9
|
from .edge_classes import MFExchanges, MFExchange
|
|
10
10
|
|
|
11
|
-
log = getLogger(__name__)
|
|
12
|
-
|
|
13
11
|
|
|
14
12
|
INHERITED_FIELDS = [
|
|
15
13
|
"database",
|
|
@@ -41,7 +39,7 @@ class MFActivity(Activity):
|
|
|
41
39
|
data_already_set (bool, optional): Whether the data is already set. Defaults to False.
|
|
42
40
|
force_insert (bool, optional): Whether to force an insert operation. Defaults to False.
|
|
43
41
|
"""
|
|
44
|
-
|
|
42
|
+
logger.debug(f"Saving {self.__class__.__name__}: {self}")
|
|
45
43
|
super().save(signal, data_already_set, force_insert)
|
|
46
44
|
|
|
47
45
|
def delete(self, signal: bool = True):
|
|
@@ -53,7 +51,7 @@ class MFActivity(Activity):
|
|
|
53
51
|
Args:
|
|
54
52
|
signal (bool, optional): Whether to send a signal after deletion. Defaults to True.
|
|
55
53
|
"""
|
|
56
|
-
|
|
54
|
+
logger.debug(f"Deleting {self.__class__.__name__}: {self}")
|
|
57
55
|
super().delete(signal)
|
|
58
56
|
|
|
59
57
|
@property
|
|
@@ -206,7 +204,7 @@ class Process(MFActivity):
|
|
|
206
204
|
self.allocate()
|
|
207
205
|
|
|
208
206
|
if changed_fields := [field for field in INHERITED_FIELDS if self.get(field) != old.data.get(field)]:
|
|
209
|
-
|
|
207
|
+
logger.info(f"Updating inherited fields {changed_fields} for products of process {self}")
|
|
210
208
|
for product in self.products():
|
|
211
209
|
for field in changed_fields:
|
|
212
210
|
product._set_inherited(field, self.get(field))
|
|
@@ -305,7 +303,7 @@ class Process(MFActivity):
|
|
|
305
303
|
normalize = set(prop.get("normalize", True) for prop in properties)
|
|
306
304
|
|
|
307
305
|
if len(units) > 1 or len(normalize) > 1:
|
|
308
|
-
|
|
306
|
+
logger.warning(f"Property {name} has inconsistent units or normalization across products.")
|
|
309
307
|
|
|
310
308
|
return {
|
|
311
309
|
"unit": units.pop() if units else "unitless",
|
|
@@ -360,7 +358,7 @@ class Process(MFActivity):
|
|
|
360
358
|
ValueError: If no allocation strategy is found.
|
|
361
359
|
"""
|
|
362
360
|
if self.get("skip_allocation"):
|
|
363
|
-
|
|
361
|
+
logger.debug(f"Skipping allocation for {repr(self)} (id: {self.id})")
|
|
364
362
|
return
|
|
365
363
|
|
|
366
364
|
from . import allocation_strategies, property_allocation
|
|
@@ -376,7 +374,7 @@ class Process(MFActivity):
|
|
|
376
374
|
"Can't find `default_allocation` in input arguments, or process/database metadata."
|
|
377
375
|
)
|
|
378
376
|
|
|
379
|
-
|
|
377
|
+
logger.debug(f"Allocating {repr(self)} (id: {self.id}) with strategy {strategy_label}")
|
|
380
378
|
|
|
381
379
|
alloc_function = allocation_strategies.get(strategy_label, property_allocation(strategy_label))
|
|
382
380
|
alloc_function(self)
|
|
@@ -439,7 +437,7 @@ class Product(MFActivity):
|
|
|
439
437
|
|
|
440
438
|
# Check if the `processor` is the same as the one in the production edge otherwise update it
|
|
441
439
|
if not created and edge.output != self["processor"]:
|
|
442
|
-
|
|
440
|
+
logger.info(f"Switching processor for {self}")
|
|
443
441
|
edge.output = self["processor"]
|
|
444
442
|
edge.save()
|
|
445
443
|
|
|
@@ -500,7 +498,7 @@ class Product(MFActivity):
|
|
|
500
498
|
excs = self.exchanges(kinds=["production"], reverse=True)
|
|
501
499
|
|
|
502
500
|
if len(excs) > 1:
|
|
503
|
-
|
|
501
|
+
logger.warning(f"Multiple processing edges found for product {self['code']}.")
|
|
504
502
|
return None
|
|
505
503
|
if len(excs) == 0:
|
|
506
504
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bw-functional
|
|
3
|
-
Version:
|
|
3
|
+
Version: 0b97
|
|
4
4
|
Summary: Code for handling multifunctional activities in Brightway
|
|
5
5
|
Author-email: Chris Mutel <cmutel@gmail.com>, Marin Visscher <m.r.visscher@cml.leidenuniv.nl>
|
|
6
6
|
Maintainer-email: Marin Visscher <m.r.visscher@cml.leidenuniv.nl>
|
|
@@ -23,6 +23,8 @@ Requires-Dist: blinker
|
|
|
23
23
|
Requires-Dist: bw2data>=4.0.1
|
|
24
24
|
Requires-Dist: bw2io>=0.9.1
|
|
25
25
|
Requires-Dist: bw_processing>=0.9.6
|
|
26
|
+
Requires-Dist: loguru
|
|
27
|
+
Requires-Dist: pandas
|
|
26
28
|
Provides-Extra: testing
|
|
27
29
|
Requires-Dist: bw-functional; extra == "testing"
|
|
28
30
|
Requires-Dist: bw2calc>=2.0.1; extra == "testing"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|