def resetParams(db_name): """Reset project and activity parameters""" _param_registry().clear() ProjectParameter.delete().execute() ActivityParameter.delete().execute() DatabaseParameter.delete().execute() Group.delete().execute()
def test_edit_database_params(qtbot, monkeypatch): table = DataBaseParameterTable() qtbot.addWidget(table) table.model.sync() # Fill rows with new variables monkeypatch.setattr( QtWidgets.QInputDialog, "getText", staticmethod(lambda *args, **kwargs: ("test_db1", True))) table.model.handle_parameter_rename(table.proxy_model.index(0, 0)) table.model.setData(table.model.index(0, 2), "test_project + 3.5") monkeypatch.setattr( QtWidgets.QInputDialog, "getText", staticmethod(lambda *args, **kwargs: ("test_db2", True))) table.model.handle_parameter_rename(table.proxy_model.index(1, 0)) table.model.setData(table.model.index(1, 2), "test_db1 ** 2") monkeypatch.setattr( QtWidgets.QInputDialog, "getText", staticmethod(lambda *args, **kwargs: ("test_db3", True))) table.model.handle_parameter_rename(table.proxy_model.index(2, 0)) table.model.setData(table.model.index(2, 1), "8.5") table.model.setData(table.model.index(2, 3), "testdb") # 5 + 3.5 = 8.5 -> 8.5 ** 2 = 72.25 assert DatabaseParameter.get(name="test_db2").amount == 72.25 # There are two parameters for `biosphere3` and one for `testdb` assert (DatabaseParameter.select().where( DatabaseParameter.database == "biosphere3").count()) == 2 assert (DatabaseParameter.select().where( DatabaseParameter.database == "testdb").count()) == 1
def test_create_database_params(qtbot): """ Create three database parameters Does not user the overarching application due to mouseClick failing """ assert DatabaseParameter.select().count() == 0 project_db_tab = ParameterDefinitionTab() qtbot.addWidget(project_db_tab) project_db_tab.build_tables() table = project_db_tab.database_table # Open the database foldout assert table.isHidden() with qtbot.waitSignal(project_db_tab.show_database_params.stateChanged, timeout=1000): qtbot.mouseClick(project_db_tab.show_database_params, QtCore.Qt.LeftButton) assert not table.isHidden() signal_list = [ signals.parameters_changed, signals.parameters_changed, signals.parameters_changed ] # Generate a few database parameters with qtbot.waitSignals(signal_list, timeout=1000): qtbot.mouseClick(project_db_tab.new_database_param, QtCore.Qt.LeftButton) qtbot.mouseClick(project_db_tab.new_database_param, QtCore.Qt.LeftButton) qtbot.mouseClick(project_db_tab.new_database_param, QtCore.Qt.LeftButton) # First created parameter is named 'param_2' assert table.model.index(0, 0).data() == "param_2" assert table.rowCount() == 3 assert DatabaseParameter.select().count() == 3
def write_database_parameters(self, activate_parameters=False, delete_existing=True): if activate_parameters: if self.database_parameters is not None: if delete_existing: DatabaseParameter.delete().where(DatabaseParameter.database == self.db_name).execute() parameters.new_database_parameters(self.database_parameters, self.db_name) elif self.database_parameters: self.metadata['parameters'] = self.database_parameters
def test_append_package(): ProjectParameter.create( name="p1", amount=1, ) ProjectParameter.create( name="p2", amount=1, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("project") pbm.load_parameter_data() pbm.calculate_static() for obj in pbm.data.values(): obj['amount'] = 10 _, dirpath = pbm.save_presample('project-test') pp = PresamplesPackage(dirpath) assert len(pp) == 1 assert pp.parameters['project__p1'] == 10 Database("db").register() Group.create(name="D", order=[]) DatabaseParameter.create( database="db", name="db1", formula="2 * p1", amount=2, ) DatabaseParameter.create( database="db", name="db2", amount=2, ) ActivityParameter.create( group="D", database="db", code="D1", name="d1", formula="p1 + db1", amount=3, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("D") pbm.load_existing(dirpath) expected = {'project__p1': 10, 'project__p2': 10} assert pbm.global_params == expected pbm.load_parameter_data() pbm.data = {'D__d1': pbm.data['D__d1']} pbm.data['D__d1']['amount'] = 12 _, dp = pbm.append_presample(dirpath, 'D-test') assert dp == dirpath pp = PresamplesPackage(dirpath) assert len(pp) == 2 assert pp.parameters['D__d1'] == 12 assert pp.parameters['project__p1'] == 10
def resetParams(db_name=None): """Clear parameters in live memory (registry) and on disk. Clear either all params (project and all db params) or db params from a single database (if db_name provided)""" _param_registry().clear(db_name) if db_name is None: ProjectParameter.delete().execute() ActivityParameter.delete().execute() DatabaseParameter.delete().execute() else: ActivityParameter.delete().where( ActivityParameter.database == db_name).execute() DatabaseParameter.delete().where( DatabaseParameter.database == db_name).execute() Group.delete().execute()
def recalculate_database_parameters(self, database: str, global_params: dict = None ) -> Optional[dict]: new_values = self.get_altered_values(database) if global_params is None: global_params = {} data = DatabaseParameter.load(database) if not data: return for name, amount in new_values.items(): data[name]["amount"] = amount new_symbols = get_new_symbols(data.values(), set(data)) missing = new_symbols.difference(global_params) if missing: raise MissingName( "The following variables aren't defined:\n{}".format( "|".join(missing))) glo = self._static(global_params, needed=new_symbols) if new_symbols else None ParameterSet(data, glo).evaluate_and_set_amount_field() return self._prune_result_data(data)
def get_usable_parameters(self): """ Use the `key` set for the table to determine the database and group of the activity, using that information to constrain the usable parameters. """ project = ([k, v, "project"] for k, v in ProjectParameter.static().items()) if self.key is None: return project database = ([k, v, "database"] for k, v in DatabaseParameter.static(self.key[0]).items()) # Determine if the activity is already part of a parameter group. query = (Group.select().join( ActivityParameter, on=(Group.name == ActivityParameter.group)).where( ActivityParameter.database == self.key[0], ActivityParameter.code == self.key[1]).distinct()) if query.exists(): group = query.get() # First, build a list for parameters in the same group activity = ([p.name, p.amount, "activity"] for p in ActivityParameter.select().where( ActivityParameter.group == group.name)) # Then extend the list with parameters from groups in the `order` # field additions = ([p.name, p.amount, "activity"] for p in ActivityParameter.select().where( ActivityParameter.group << group.order)) activity = itertools.chain(activity, additions) else: activity = [] return itertools.chain(project, database, activity)
def __init__(self): self._project_params = ProjectParameter.load() self._db_params = { p.database: DatabaseParameter.load(p.database) for p in DatabaseParameter.select(DatabaseParameter.database).distinct() } self._act_params = { p.group: ActivityParameter.load(p.group) for p in ActivityParameter.select(ActivityParameter.group).distinct() } self._distinct_act_params = [ p for p in (ActivityParameter .select(ActivityParameter.group, ActivityParameter.database) .distinct()) ] self._exc_params = [p for p in ParameterizedExchange.select()]
def get_usable_parameters(): """ Include the project parameters, and generate database parameters. """ project = ProjectParameterTable.get_usable_parameters() database = ([p.name, p.amount, "database ({})".format(p.database)] for p in DatabaseParameter.select()) return itertools.chain(project, database)
def process_brightway_parameters() -> Iterable[tuple]: """ Converts brightway parameters of all types into a simple structure in order of possible dependency. """ return itertools.chain( ((p.name, "project", p.amount) for p in ProjectParameter.select()), ((p.name, p.database, p.amount) for p in DatabaseParameter.select()), ((p.name, p.group, p.amount) for p in ActivityParameter.select()))
def get_database_parameters(self): data = [ o.dict for o in DatabaseParameter.select().where( DatabaseParameter.database == self.db.name ) ] return self.order_dicts(data, "parameter")
def build_df(cls) -> pd.DataFrame: """ Build a dataframe using the DatabaseParameters set in brightway """ data = [ cls.parse_parameter(p) for p in DatabaseParameter.select() ] df = pd.DataFrame(data, columns=cls.combine_columns()) return df
def get_interpreter(self) -> Interpreter: """ Take the interpreter from the ProjectParameterTable and add (potentially overwriting) all database symbols for the selected index. """ interpreter = ProjectParameterTable.get_interpreter() db_name = self.get_current_database() interpreter.symtable.update(DatabaseParameter.static(db_name)) return interpreter
def recalculate_scenario( self, scenario_values: Iterable[float]) -> (np.ndarray, np.ndarray): """ Convenience function that takes new parameter values and returns a fully-formed set of exchange amounts and indices. All parameter types are recalculated in turn before interpreting the ParameterizedExchange formulas into amounts. """ self.param_values = replace_amounts(self.param_values, scenario_values) global_project = self.recalculate_project_parameters() all_db = {} for p in DatabaseParameter.select( DatabaseParameter.database).distinct(): db = self.recalculate_database_parameters(p.database, global_project) all_db[p.database] = {x: y for x, y in db.items()} if db else {} complete_data = [] complete_indices = [] for p in ActivityParameter.select( ActivityParameter.group, ActivityParameter.database).distinct(): combination = {x: y for x, y in global_project.items() } if global_project else {} combination.update(all_db.get(p.database, {})) act = self.recalculate_activity_parameters(p.group, combination) combination.update(act) recalculated = self.recalculate_exchanges( p.group, global_params=combination) # If the parameter group contains no ParameterizedExchanges, skip. if not recalculated: continue # `data` contains the recalculated amounts for the exchanges. ids, data = zip(*recalculated) indices = [] for pk in ids: exc = ExchangeDataset.get_by_id(pk) input_key = (exc.input_database, exc.input_code) output_key = (exc.output_database, exc.output_code) if exc.input_database == bw.config.biosphere: indices.append((input_key, output_key, "biosphere")) else: indices.append((input_key, output_key, "technosphere")) complete_data.extend(data) complete_indices.extend(indices) # After recalculating all the exchanges and adding all samples and indices # to lists, format them according to presamples requirements: # eg: samples as a column of floats and indices as a row of tuples. samples = np.array(complete_data) samples = samples.reshape(1, -1).T indices = np.array(complete_indices) return samples, indices
def __init__(self, seed: Optional[int] = None): super().__init__() parameters = itertools.chain(ProjectParameter.select(), DatabaseParameter.select(), ActivityParameter.select()) self.uncertainties = UncertaintyBase.from_dicts( *[getattr(p, "data", {}) for p in parameters]) self.mc_generator = MCRandomNumberGenerator(self.uncertainties, seed=seed)
def from_bw_parameters(cls) -> 'Parameters': """Construct a Parameters list from brightway2 parameters.""" return cls(chain( (Parameter(p.name, "project", p.amount, "project") for p in ProjectParameter.select()), (Parameter(p.name, p.database, p.amount, "database") for p in DatabaseParameter.select()), (Parameter(p.name, p.group, p.amount, "activity") for p in ActivityParameter.select()), ))
def test_create_database_params(qtbot): """ Create three database parameters Does not user the overarching application due to mouseClick failing """ assert DatabaseParameter.select().count() == 0 project_db_tab = ParameterDefinitionTab() qtbot.addWidget(project_db_tab) project_db_tab.build_tables() table = project_db_tab.database_table # Open the database foldout assert not table.isHidden() with qtbot.waitSignal(project_db_tab.show_database_params.stateChanged, timeout=1000): qtbot.mouseClick(project_db_tab.show_database_params, QtCore.Qt.LeftButton) assert table.isHidden() project_db_tab.show_database_params.toggle() # Generate a few database parameters bw.parameters.new_database_parameters([ { "name": "param_2", "amount": 1.0 }, { "name": "param_3", "amount": 1.0 }, { "name": "param_4", "amount": 1.0 }, ], database="biosphere3") table.model.sync() # First created parameter is named 'param_2' assert table.model.index(0, 0).data() == "param_2" assert table.rowCount() == 3 assert DatabaseParameter.select().count() == 3
def sync(self, *args, **kwargs) -> None: self.beginResetModel() self.root.clear() self.endResetModel() self._data.update({ "project": ProjectParameter.select().iterator(), "database": DatabaseParameter.select().iterator(), "activity": ActivityParameter.select().iterator(), }) self.setup_model_data() self.updated.emit()
def test_edit_database_params(qtbot): table = DataBaseParameterTable() qtbot.addWidget(table) table.sync(table.build_df()) # Fill rows with new variables table.rename_parameter(table.proxy_model.index(0, 0), "test_db1") table.model.setData(table.model.index(0, 2), "test_project + 3.5") table.rename_parameter(table.proxy_model.index(1, 0), "test_db2") table.model.setData(table.model.index(1, 2), "test_db1 ** 2") table.rename_parameter(table.proxy_model.index(2, 0), "test_db3") table.model.setData(table.model.index(2, 1), "8.5") table.model.setData(table.model.index(2, 3), "testdb") # 5 + 3.5 = 8.5 -> 8.5 ** 2 = 72.25 assert DatabaseParameter.get(name="test_db2").amount == 72.25 # There are two parameters for `biosphere3` and one for `testdb` assert (DatabaseParameter.select() .where(DatabaseParameter.database == "biosphere3").count()) == 2 assert (DatabaseParameter.select() .where(DatabaseParameter.database == "testdb").count()) == 1
def add_parameter(self) -> None: """ Build a new parameter and immediately store it. """ counter = (ProjectParameter.select().count() + DatabaseParameter.select().count()) try: bw.parameters.new_project_parameters([ {"name": "param_{}".format(counter + 1), "amount": 1.0} ], False) signals.parameters_changed.emit() except ValueError as e: simple_warning_box(self, "Name already in use!", str(e))
def add_parameter(self) -> None: """ Add a new database parameter to the dataframe NOTE: The new parameter uses the first database it can find. """ counter = (ProjectParameter.select().count() + DatabaseParameter.select().count()) database = next(iter(bw.databases)) try: bw.parameters.new_database_parameters([ {"name": "param_{}".format(counter + 1), "amount": 1.0} ], database, False) signals.parameters_changed.emit() except ValueError as e: simple_warning_box(self, "Name already in use!", str(e))
def get_interpreter(self) -> Interpreter: """ Use the activity key to determine which symbols are added to the formula interpreter. """ interpreter = Interpreter() act = ActivityParameter.get_or_none(database=self.key[0], code=self.key[1]) if act: interpreter.symtable.update( ActivityParameter.static(act.group, full=True)) else: print("No parameter found for {}, creating one on formula save". format(self.key)) interpreter.symtable.update(ProjectParameter.static()) interpreter.symtable.update(DatabaseParameter.static(self.key[0])) return interpreter
def test_delete_database_params(qtbot): """ Attempt to delete a parameter. """ project_db_tab = ParameterDefinitionTab() qtbot.addWidget(project_db_tab) project_db_tab.build_tables() table = project_db_tab.database_table # Check that we can delete the parameter and remove it. proxy = table.proxy_model.index(1, 0) assert table.get_parameter(proxy).is_deletable() table.delete_parameter(proxy) # Now we have two rows left assert table.rowCount() == 2 assert DatabaseParameter.select().count() == 2
def test_database_delete_parameters(): db = DatabaseChooser("example") db.register() a = db.new_activity(code="A", name="An activity") a.save() b = db.new_activity(code="B", name="Another activity") b.save() a.new_exchange( amount=0, input=b, type="technosphere", formula="foo * bar + 4" ).save() database_data = [ {"name": "red", "formula": "(blue ** 2) / 5",}, {"name": "blue", "amount": 12}, ] parameters.new_database_parameters(database_data, "example") activity_data = [ { "name": "reference_me", "formula": "sqrt(red - 20)", "database": "example", "code": "B", }, { "name": "bar", "formula": "reference_me + 2", "database": "example", "code": "A", }, ] parameters.new_activity_parameters(activity_data, "my group") parameters.add_exchanges_to_group("my group", a) assert ActivityParameter.select().count() == 2 assert ParameterizedExchange.select().count() == 1 assert DatabaseParameter.select().count() == 2 assert len(parameters) == 4 del databases["example"] assert not len(parameters) assert not ParameterizedExchange.select().count()
def export_db(db_name, filename) : """Export Db and linked parameters""" db = bw.Database(db_name) db_params = DatabaseParameter.select().where(DatabaseParameter.database == db_name) # Export Db params db.metadata["database_parameters"] = [param_data(param) for param in db_params] # List of all project params used in this dataset used_project_params = list(param.name for param in _listParams(db_name) if param.dbname is None) if len(used_project_params) > 0 : error('Warning : this DB uses project parameters that are exported as well and might override project params at import time : ', used_project_params) proj_params = list(ProjectParameter.get(ProjectParameter.name==name) for name in used_project_params) db.metadata["project_parameters"] = [param_data(param) for param in proj_params] BW2Package._write_file(filename, [BW2Package._prepare_obj(db, False)])
def test_database_delete_parameters(): db = DatabaseChooser("example") db.register() a = db.new_activity(code="A", name="An activity") a.save() b = db.new_activity(code="B", name="Another activity") b.save() a.new_exchange(amount=0, input=b, type="technosphere", formula="foo * bar + 4").save() database_data = [{ 'name': 'red', 'formula': '(blue ** 2) / 5', }, { 'name': 'blue', 'amount': 12 }] parameters.new_database_parameters(database_data, "example") activity_data = [{ 'name': 'reference_me', 'formula': 'sqrt(red - 20)', 'database': 'example', 'code': "B", }, { 'name': 'bar', 'formula': 'reference_me + 2', 'database': 'example', 'code': "A", }] parameters.new_activity_parameters(activity_data, "my group") parameters.add_exchanges_to_group("my group", a) assert ActivityParameter.select().count() == 2 assert ParameterizedExchange.select().count() == 1 assert DatabaseParameter.select().count() == 2 assert len(parameters) == 4 del databases['example'] assert not len(parameters) assert not ParameterizedExchange.select().count()
def sync(self) -> None: self.data.update({ "project": ProjectParameter.select().iterator(), "database": DatabaseParameter.select().iterator(), "activity": ActivityParameter.select().iterator(), })
def test_load_existing_complete(): # Use same structure as in complicated example, but pre-create some presamples packages # Start with `project` ProjectParameter.create( name="p1", amount=1, ) ProjectParameter.create( name="p2", amount=1, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("project") pbm.load_parameter_data() result = pbm.calculate_static() expected = {'project__p1': 1, 'project__p2': 1} assert result == expected for obj in pbm.data.values(): obj['amount'] = 10 _, dirpath_project = pbm.save_presample('project-test') pp = PresamplesPackage(dirpath_project) assert len(pp) == 1 assert pp.parameters['project__p1'] == 10 # We will also do group 'D'; this will include database parameters, which will we purge ourselves Database("db").register() Group.create(name="D", order=[]) DatabaseParameter.create( database="db", name="db1", formula="2 * p1", amount=2, ) DatabaseParameter.create( database="db", name="db2", amount=2, ) ActivityParameter.create( group="D", database="db", code="D1", name="d1", formula="p1 + db1", amount=3, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("D") pbm.load_existing(dirpath_project) expected = {'project__p1': 10, 'project__p2': 10} assert pbm.global_params == expected pbm.load_parameter_data() expected = { 'D__d1': { 'database': 'db', 'code': 'D1', 'formula': '(project__p1 + db__db1)', 'amount': 3.0, 'original': 'd1' }, 'db__db1': { 'database': 'db', 'formula': '(2 * project__p1)', 'amount': 2.0, 'original': 'db1' }, 'db__db2': { 'database': 'db', 'amount': 2.0, 'original': 'db2' }, } assert pbm.data == expected # Want to calculate database parameters dynamically pbm.data = {'D__d1': pbm.data['D__d1']} pbm.data['D__d1']['amount'] = 12 _, dirpath_d = pbm.save_presample('D-test') pp = PresamplesPackage(dirpath_d) assert len(pp) == 1 assert pp.parameters['D__d1'] == 12 # Create rest of parameters Group.create(name="E", order=[]) Group.create(name="B", order=["E"]) Group.create(name="C", order=["D", "E"]) Group.create(name="A", order=["C", "B"]) ActivityParameter.create( group="E", database="db", code="E1", name="e1", formula="p1 + p2 + db2", amount=4, ) ActivityParameter.create( group="C", database="db", code="C1", name="c1", formula="(e1 - d1) * 5", amount=5, ) ActivityParameter.create( group="B", database="db", code="B1", name="b1", formula="e1 * 2 - 2", amount=6, ) ActivityParameter.create( group="A", database="db", code="A1", name="a1", formula="b1 + c1 - db1 - 2", amount=7, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("A") pbm.load_existing(dirpath_project) pbm.load_existing(dirpath_d) pbm.load_parameter_data() expected = { 'A__a1': { 'amount': 7.0, 'code': 'A1', 'database': 'db', 'formula': '(((B__b1 + C__c1) - db__db1) - 2)', 'original': 'a1' }, 'B__b1': { 'amount': 6.0, 'code': 'B1', 'database': 'db', 'formula': '((E__e1 * 2) - 2)', 'original': 'b1' }, 'C__c1': { 'amount': 5.0, 'code': 'C1', 'database': 'db', 'formula': '((E__e1 - D__d1) * 5)', 'original': 'c1' }, 'E__e1': { 'amount': 4.0, 'code': 'E1', 'database': 'db', 'formula': '((project__p1 + project__p2) + db__db2)', 'original': 'e1' }, 'db__db1': { 'amount': 2.0, 'database': 'db', 'formula': '(2 * project__p1)', 'original': 'db1' }, 'db__db2': { 'amount': 2.0, 'database': 'db', 'original': 'db2' }, } assert pbm.data == expected result = pbm.calculate_static() expected = { 'A__a1': 70.0, 'B__b1': 42.0, 'C__c1': 50.0, 'D__d1': 12.0, 'E__e1': 22.0, 'db__db1': 20.0, 'db__db2': 2.0, 'project__p1': 10, 'project__p2': 10, } assert result == expected pbm = ParameterizedBrightwayModel("A") pbm.load_existing(dirpath_project, only=['project__p1']) pbm.load_existing(dirpath_d) pbm.load_parameter_data() assert 'project__p2' in pbm.data assert 'project__p1' not in pbm.data
def test_chain_loading_complicated(): Database("db").register() Group.create(name="D", order=[]) Group.create(name="E", order=[]) Group.create(name="B", order=["E"]) Group.create(name="C", order=["D", "E"]) Group.create(name="A", order=["C", "B"]) ProjectParameter.create( name="p1", amount=1, ) ProjectParameter.create( name="p2", amount=1, ) DatabaseParameter.create( database="db", name="db1", formula="2 * p1", amount=2, ) DatabaseParameter.create( database="db", name="db2", amount=2, ) ActivityParameter.create( group="D", database="db", code="D1", name="d1", formula="p1 + db1", amount=3, ) ActivityParameter.create( group="E", database="db", code="E1", name="e1", formula="p1 + p2 + db2", amount=4, ) ActivityParameter.create( group="C", database="db", code="C1", name="c1", formula="(e1 - d1) * 5", amount=5, ) ActivityParameter.create( group="B", database="db", code="B1", name="b1", formula="e1 * 2 - 2", amount=6, ) ActivityParameter.create( group="A", database="db", code="A1", name="a1", formula="b1 + c1 - db1 - 2", amount=7, ) parameters.recalculate() pbm = ParameterizedBrightwayModel("A") pbm.load_parameter_data() expected = { 'A__a1': { 'amount': 7.0, 'code': 'A1', 'database': 'db', 'formula': '(((B__b1 + C__c1) - db__db1) - 2)', 'original': 'a1' }, 'B__b1': { 'amount': 6.0, 'code': 'B1', 'database': 'db', 'formula': '((E__e1 * 2) - 2)', 'original': 'b1' }, 'C__c1': { 'amount': 5.0, 'code': 'C1', 'database': 'db', 'formula': '((E__e1 - D__d1) * 5)', 'original': 'c1' }, 'D__d1': { 'amount': 3.0, 'code': 'D1', 'database': 'db', 'formula': '(project__p1 + db__db1)', 'original': 'd1' }, 'E__e1': { 'amount': 4.0, 'code': 'E1', 'database': 'db', 'formula': '((project__p1 + project__p2) + db__db2)', 'original': 'e1' }, 'db__db1': { 'amount': 2.0, 'database': 'db', 'formula': '(2 * project__p1)', 'original': 'db1' }, 'db__db2': { 'amount': 2.0, 'database': 'db', 'original': 'db2' }, 'project__p1': { 'amount': 1.0, 'original': 'p1' }, 'project__p2': { 'amount': 1.0, 'original': 'p2' } } assert pbm.data == expected