Skip to main content

An alternate backend for Brightway that allows richer edge descriptions that don't map 1-to-1 to matrix values.

Project description

edge-of-the-world (bw_eotw)

PyPI Python Version License Tests

An alternate Brightway backend with richer edge descriptions. Instead of each exchange mapping directly to one matrix cell, edges carry an interpreter key that controls how they expand at processing time — one edge can become multiple matrix entries, or its value can be selected from a config-driven lookup table.

Installation

pip install bw_eotw

Requires Python ≥ 3.9 and bw2data >= 4.0.

Quickstart

import bw2data
import bw_eotw  # registers the "eotw" backend on import

bw2data.projects.set_current("my-project")

db = bw2data.Database("my-db", backend="eotw")
db.register()

node = db.new_node(name="electricity", type="process", unit="kWh")
node.save()

# A plain edge — identical to a standard bw2data exchange
node.new_edge(
    input=other_node,
    type="technosphere",
    interpreter="singlevalue",
    amount=2.5,
).save()

db.process()

Core concepts

RichEdgesBackend

RichEdgesBackend is a drop-in replacement for Brightway's SQLiteBackend. The only behavioural difference is that edges with an interpreter key are dispatched to the registered interpreter during process(). Edges without that key are passed through unchanged, so existing datasets need no migration.

Create a database with this backend:

db = bw2data.Database("my-db", backend="eotw")

write() is disabled — use db.new_node() / node.new_edge() to build the database incrementally.

Interpreters

An interpreter is a callable registered under a name. When process() encounters an edge with "interpreter": "name", it calls the interpreter with the edge data and the active config, and writes whatever MatrixEntry objects the interpreter yields.

Built-in interpreters

Name What it does
singlevalue Single matrix cell; identical to a plain bw2data exchange
loss Main flow + proportional loss component in the same cell
provider_mix Splits demand across multiple providers by fractional share
temporal Picks a value from a year-keyed dict; year comes from config
temporal_scenario Picks a value from a scenario × year nested dict
singlevalue
node.new_edge(
    input=other_node, type="technosphere",
    interpreter="singlevalue", amount=1.5,
).save()
loss
node.new_edge(
    input=other_node, type="technosphere",
    interpreter="loss",
    amount=1.0,       # main flow
    loss_factor=0.05, # 5 % loss; must be a plain number in [0, 1]
).save()

Yields two entries into the same matrix cell: amount and amount * loss_factor.

provider_mix
node.new_edge(
    input=dummy_node, type="technosphere",
    interpreter="provider_mix",
    product_name="electricity",
    amount=2.0,
    mix=[
        {"input": provider_a.id, "share": 0.60},
        {"input": provider_b.id, "share": 0.40},
    ],
).save()

Shares must sum to 1. All input nodes must be in the same database. Pass Node instances or integer IDs — normalize_edge converts them automatically on save.

temporal
node.new_edge(
    input=other_node, type="technosphere",
    interpreter="temporal",
    temporal_values={2010: 0.3, 2020: 0.4, 2030: 0.6},
    default_year=2020,  # used when config has no "year" key
).save()

Year lookup order: config["year"]edge["default_year"]KeyError.

temporal_scenario
node.new_edge(
    input=other_node, type="technosphere",
    interpreter="temporal_scenario",
    scenario_temporal_values={
        "baseline":   {2020: 1.00, 2030: 0.85},
        "optimistic": {2020: 0.80, 2030: 0.60},
    },
    default_year=2020,
).save()

config["scenario"] is required; config["year"] falls back to default_year.

Config and cache invalidation

Some interpreters (e.g. temporal, temporal_scenario) need a config dict at processing time. Set it before calling process() or prepare_lca_inputs():

# Plain call — stays active until changed
db.set_config({"year": 2030})
db.process()

# Context manager — restores previous config on exit
with db.set_config({"year": 2030, "scenario": "optimistic"}):
    fu, data_objs, remapping = bw2data.prepare_lca_inputs(...)

set_config stores the config in database metadata and appends a short hash to the processed filename, so different configs produce different cached datapackages. Stale variants are cleaned up automatically when the database is reprocessed.

To clear the active config:

db.set_config(None)

Custom interpreters

Subclass Interpreter and decorate with @register:

from bw_eotw import Interpreter, register
from bw_eotw.matrix_entry import MatrixEntry

@register("my_interpreter")
class MyInterpreter(Interpreter):
    def __call__(self, edge_data, config):
        # yield one or more MatrixEntry objects
        yield MatrixEntry.from_edge_value(edge_data, edge_data)

    def iter_node_ids(self, edge_data):
        yield from ()  # yield any extra integer node IDs embedded in edge_data

Override normalize to convert bw2data Node instances to integer IDs before save, validate to add structural checks (call super().validate() to keep the same-database invariant), and repr_parts / html_rows for notebook display.

Set requires_config = True if the interpreter cannot run without an active config — resolve() will raise ValueError early rather than failing mid-process.

Contributing

Contributions are welcome. See CONTRIBUTING.md.

License

Distributed under the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bw_eotw-0.1.0.tar.gz (28.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bw_eotw-0.1.0-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

Details for the file bw_eotw-0.1.0.tar.gz.

File metadata

  • Download URL: bw_eotw-0.1.0.tar.gz
  • Upload date:
  • Size: 28.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for bw_eotw-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d30d305b030527e1a7bb9249cb350be6f6b2a2a0f9593f1607aa688e06947dcb
MD5 2c4ed8775d20573315f1fcdbcc7a072a
BLAKE2b-256 83ce992ac559e24355cbf9b6a36d4fd9461f95acf38ee4be36ea88b4b9ec71f7

See more details on using hashes here.

File details

Details for the file bw_eotw-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bw_eotw-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for bw_eotw-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1ad997fe4dfa4addec9bfac6cc16cd8fc810f3c544ee234715553a8972008f1a
MD5 27afe1c37409c6224ce496176e4fae77
BLAKE2b-256 e1eb01c868216658bf6e9ecb955b59ce026e3fe96057777003fb47198e67cf5e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page