flextool 4.0.0__py3-none-any.whl
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.
- flextool/__init__.py +41 -0
- flextool/_mem_sampler.py +193 -0
- flextool/_resources.py +43 -0
- flextool/calibrate/__init__.py +51 -0
- flextool/calibrate/__main__.py +11 -0
- flextool/calibrate/_cli.py +316 -0
- flextool/calibrate/_db_alt.py +166 -0
- flextool/calibrate/_final_outputs.py +110 -0
- flextool/calibrate/_guard.py +151 -0
- flextool/calibrate/_loop.py +558 -0
- flextool/calibrate/_readers.py +223 -0
- flextool/calibrate/_report.py +263 -0
- flextool/calibrate/_sizing.py +699 -0
- flextool/calibrate/_solve.py +134 -0
- flextool/calibrate/_solve_status.py +495 -0
- flextool/cli/__init__.py +9 -0
- flextool/cli/_console.py +51 -0
- flextool/cli/_timing.py +147 -0
- flextool/cli/cmd_execute_flextool_workflow.py +187 -0
- flextool/cli/cmd_export_to_tabular.py +56 -0
- flextool/cli/cmd_import_sensitivities.py +75 -0
- flextool/cli/cmd_migrate_database.py +13 -0
- flextool/cli/cmd_open_results_db.py +269 -0
- flextool/cli/cmd_read_matpower.py +66 -0
- flextool/cli/cmd_read_old_flextool.py +63 -0
- flextool/cli/cmd_read_self_describing_tabular_input.py +50 -0
- flextool/cli/cmd_read_tabular_input.py +81 -0
- flextool/cli/cmd_run_flextool.py +1095 -0
- flextool/cli/cmd_scenario_results.py +284 -0
- flextool/cli/cmd_solve_mps.py +169 -0
- flextool/cli/cmd_update_flextool.py +17 -0
- flextool/cli/cmd_write_outputs.py +125 -0
- flextool/common_utils/__init__.py +1 -0
- flextool/common_utils/plot_mem_shape.py +77 -0
- flextool/common_utils/precision.py +451 -0
- flextool/decomposition/__init__.py +0 -0
- flextool/decomposition/region_decomposition.py +128 -0
- flextool/decomposition/region_filter.py +1261 -0
- flextool/engine_polars/__init__.py +110 -0
- flextool/engine_polars/_axis_enums.py +742 -0
- flextool/engine_polars/_benders.py +3462 -0
- flextool/engine_polars/_block_layout.py +1479 -0
- flextool/engine_polars/_blocks.py +1515 -0
- flextool/engine_polars/_commodity_ladder.py +660 -0
- flextool/engine_polars/_cumulative_invest.py +1165 -0
- flextool/engine_polars/_db_loader.py +153 -0
- flextool/engine_polars/_db_reader.py +127 -0
- flextool/engine_polars/_dc_power_flow.py +445 -0
- flextool/engine_polars/_delay.py +442 -0
- flextool/engine_polars/_derived_arithmetic.py +432 -0
- flextool/engine_polars/_derived_block.py +990 -0
- flextool/engine_polars/_derived_branch.py +769 -0
- flextool/engine_polars/_derived_existing.py +1353 -0
- flextool/engine_polars/_derived_npv.py +1297 -0
- flextool/engine_polars/_derived_params.py +9850 -0
- flextool/engine_polars/_derived_profile.py +881 -0
- flextool/engine_polars/_derived_walks.py +276 -0
- flextool/engine_polars/_determinism.py +70 -0
- flextool/engine_polars/_direct_params.py +2186 -0
- flextool/engine_polars/_dump_csvs.py +1009 -0
- flextool/engine_polars/_emit_arc_unions.py +1631 -0
- flextool/engine_polars/_emit_calc_params.py +729 -0
- flextool/engine_polars/_emit_chain_params.py +709 -0
- flextool/engine_polars/_emit_co2_accumulators.py +400 -0
- flextool/engine_polars/_emit_dispatchers.py +690 -0
- flextool/engine_polars/_emit_energy_margin.py +125 -0
- flextool/engine_polars/_emit_energy_margin_adder.py +290 -0
- flextool/engine_polars/_emit_entity_annual.py +428 -0
- flextool/engine_polars/_emit_inflow_scaling.py +1420 -0
- flextool/engine_polars/_emit_leaf_sets.py +550 -0
- flextool/engine_polars/_emit_lp_scaling.py +665 -0
- flextool/engine_polars/_emit_mid_sets.py +859 -0
- flextool/engine_polars/_emit_pdt_params.py +759 -0
- flextool/engine_polars/_emit_per_solve.py +774 -0
- flextool/engine_polars/_emit_period_calc.py +504 -0
- flextool/engine_polars/_emit_period_params.py +2398 -0
- flextool/engine_polars/_emit_provider_io.py +141 -0
- flextool/engine_polars/_emit_reserve.py +574 -0
- flextool/engine_polars/_emit_solve_time.py +311 -0
- flextool/engine_polars/_emit_solve_writers.py +1249 -0
- flextool/engine_polars/_flex_data_accumulator.py +388 -0
- flextool/engine_polars/_flex_data_provider.py +478 -0
- flextool/engine_polars/_group_slack.py +1253 -0
- flextool/engine_polars/_inmemory_reader.py +140 -0
- flextool/engine_polars/_input_source.py +336 -0
- flextool/engine_polars/_invest_seeds.py +191 -0
- flextool/engine_polars/_native_input_writer.py +100 -0
- flextool/engine_polars/_native_run_model.py +1348 -0
- flextool/engine_polars/_orchestration.py +4314 -0
- flextool/engine_polars/_output_writer.py +439 -0
- flextool/engine_polars/_param_shapes.py +1595 -0
- flextool/engine_polars/_parquet_bundle.py +723 -0
- flextool/engine_polars/_pdt_join.py +167 -0
- flextool/engine_polars/_pdt_lookup.py +547 -0
- flextool/engine_polars/_per_solve_sets.py +335 -0
- flextool/engine_polars/_projection_params.py +2056 -0
- flextool/engine_polars/_provider_keys.py +173 -0
- flextool/engine_polars/_provider_translators.py +225 -0
- flextool/engine_polars/_recursive_solve.py +703 -0
- flextool/engine_polars/_region_filter.py +2508 -0
- flextool/engine_polars/_reserve.py +649 -0
- flextool/engine_polars/_solve_acceptance.py +331 -0
- flextool/engine_polars/_solve_config.py +1001 -0
- flextool/engine_polars/_solve_context.py +885 -0
- flextool/engine_polars/_solve_handoff.py +164 -0
- flextool/engine_polars/_solve_state.py +232 -0
- flextool/engine_polars/_solver_base.py +36 -0
- flextool/engine_polars/_solver_dispatch.py +511 -0
- flextool/engine_polars/_spinedb_reader.py +1165 -0
- flextool/engine_polars/_stochastic.py +593 -0
- flextool/engine_polars/_subprocess_solve.py +1838 -0
- flextool/engine_polars/_timeline.py +1416 -0
- flextool/engine_polars/_vectorize.py +438 -0
- flextool/engine_polars/_warm.py +858 -0
- flextool/engine_polars/autoscale/__init__.py +107 -0
- flextool/engine_polars/autoscale/_config.py +218 -0
- flextool/engine_polars/autoscale/_layer2.py +1253 -0
- flextool/engine_polars/autoscale/_layer2_types.py +584 -0
- flextool/engine_polars/autoscale/_quantity_types.py +621 -0
- flextool/engine_polars/autoscale/_report.py +336 -0
- flextool/engine_polars/chain.py +259 -0
- flextool/engine_polars/input.py +6638 -0
- flextool/engine_polars/model.py +4754 -0
- flextool/env_check.py +388 -0
- flextool/export_to_tabular/__init__.py +5 -0
- flextool/export_to_tabular/db_reader.py +224 -0
- flextool/export_to_tabular/excel_writer.py +3559 -0
- flextool/export_to_tabular/export_settings.yaml +377 -0
- flextool/export_to_tabular/export_to_excel.py +227 -0
- flextool/export_to_tabular/formatting.py +543 -0
- flextool/export_to_tabular/sheet_config.py +876 -0
- flextool/gui/__init__.py +0 -0
- flextool/gui/__main__.py +118 -0
- flextool/gui/calibrate_commands.py +184 -0
- flextool/gui/calibrate_jobs.py +424 -0
- flextool/gui/check_tree.py +142 -0
- flextool/gui/cli_format.py +83 -0
- flextool/gui/config_parser.py +68 -0
- flextool/gui/data_models.py +362 -0
- flextool/gui/db_editor_integration.py +202 -0
- flextool/gui/db_version_check.py +269 -0
- flextool/gui/dialogs/__init__.py +0 -0
- flextool/gui/dialogs/add_dialog.py +1098 -0
- flextool/gui/dialogs/calibrate_dialog.py +1259 -0
- flextool/gui/dialogs/file_picker.py +473 -0
- flextool/gui/dialogs/group_picker.py +299 -0
- flextool/gui/dialogs/migration_consent_dialog.py +106 -0
- flextool/gui/dialogs/migration_progress_dialog.py +237 -0
- flextool/gui/dialogs/plot_dialog.py +459 -0
- flextool/gui/dialogs/plot_settings_picker.py +2184 -0
- flextool/gui/dialogs/project_dialog.py +426 -0
- flextool/gui/dialogs/update_dialog.py +212 -0
- flextool/gui/downsampling.py +88 -0
- flextool/gui/error_handling.py +50 -0
- flextool/gui/execution_manager.py +1715 -0
- flextool/gui/execution_window.py +1377 -0
- flextool/gui/hover_tooltip.py +111 -0
- flextool/gui/input_sources.py +730 -0
- flextool/gui/main_window.py +6181 -0
- flextool/gui/network_graph.py +215 -0
- flextool/gui/output_actions.py +393 -0
- flextool/gui/output_log_window.py +159 -0
- flextool/gui/platform_utils.py +421 -0
- flextool/gui/plot_cache.py +88 -0
- flextool/gui/plot_canvas.py +543 -0
- flextool/gui/plot_config_reader.py +272 -0
- flextool/gui/project_utils.py +100 -0
- flextool/gui/result_viewer.py +4394 -0
- flextool/gui/scenario_key.py +162 -0
- flextool/gui/scenario_lists.py +516 -0
- flextool/gui/settings_io.py +360 -0
- flextool/gui/solve_reader.py +103 -0
- flextool/gui/tree_reorder.py +88 -0
- flextool/gui/ui_metrics.py +420 -0
- flextool/input_derivation/__init__.py +281 -0
- flextool/input_derivation/_commodity_ladder.py +375 -0
- flextool/input_derivation/_commodity_ladder_sets.py +70 -0
- flextool/input_derivation/_dc_power_flow.py +377 -0
- flextool/input_derivation/_method_constants.py +77 -0
- flextool/input_derivation/_process_method.py +258 -0
- flextool/input_derivation/_specs.py +1026 -0
- flextool/input_derivation/_validators.py +321 -0
- flextool/lean_parquet.py +159 -0
- flextool/model_builder/__init__.py +5 -0
- flextool/model_builder/build_model.py +589 -0
- flextool/model_builder/encoding.py +67 -0
- flextool/model_builder/names.py +34 -0
- flextool/model_builder/profiles.py +129 -0
- flextool/plot_outputs/__init__.py +14 -0
- flextool/plot_outputs/axis_helpers.py +355 -0
- flextool/plot_outputs/color_template.py +888 -0
- flextool/plot_outputs/config.py +171 -0
- flextool/plot_outputs/format_helpers.py +345 -0
- flextool/plot_outputs/legend_helpers.py +143 -0
- flextool/plot_outputs/orchestrator.py +1141 -0
- flextool/plot_outputs/perf.py +37 -0
- flextool/plot_outputs/plan.py +1787 -0
- flextool/plot_outputs/plot_bars.py +1510 -0
- flextool/plot_outputs/plot_bars_detail.py +753 -0
- flextool/plot_outputs/plot_lines.py +951 -0
- flextool/plot_outputs/shared_manifest.py +564 -0
- flextool/plot_outputs/subplot_helpers.py +137 -0
- flextool/process_inputs/__init__.py +188 -0
- flextool/process_inputs/import_old_excel_input.json +4159 -0
- flextool/process_inputs/read_matpower.py +451 -0
- flextool/process_inputs/read_old_flextool.py +1288 -0
- flextool/process_inputs/read_self_describing_excel.py +1423 -0
- flextool/process_inputs/read_tabular_with_specification.py +1114 -0
- flextool/process_inputs/write_old_flextool_to_db.py +3077 -0
- flextool/process_inputs/write_self_describing_to_db.py +977 -0
- flextool/process_inputs/write_to_input_db.py +269 -0
- flextool/process_outputs/__init__.py +7 -0
- flextool/process_outputs/_annualize.py +55 -0
- flextool/process_outputs/_inmemory_helpers.py +292 -0
- flextool/process_outputs/_output_meta.py +672 -0
- flextool/process_outputs/calc_capacity_flows.py +107 -0
- flextool/process_outputs/calc_connections.py +136 -0
- flextool/process_outputs/calc_costs.py +260 -0
- flextool/process_outputs/calc_group_flows.py +192 -0
- flextool/process_outputs/calc_slacks.py +103 -0
- flextool/process_outputs/calc_storage_vre.py +160 -0
- flextool/process_outputs/drop_levels.py +208 -0
- flextool/process_outputs/handoff_writers.py +1315 -0
- flextool/process_outputs/out_ancillary.py +544 -0
- flextool/process_outputs/out_capacity.py +179 -0
- flextool/process_outputs/out_costs.py +334 -0
- flextool/process_outputs/out_flowgroup.py +189 -0
- flextool/process_outputs/out_flows.py +301 -0
- flextool/process_outputs/out_group.py +475 -0
- flextool/process_outputs/out_node.py +190 -0
- flextool/process_outputs/persist_realized_slice.py +601 -0
- flextool/process_outputs/process_results.py +24 -0
- flextool/process_outputs/read_highs_solution.py +2256 -0
- flextool/process_outputs/read_parameters.py +1799 -0
- flextool/process_outputs/read_sets.py +1095 -0
- flextool/process_outputs/read_variables.py +553 -0
- flextool/process_outputs/solve_order.py +81 -0
- flextool/process_outputs/spinedb_replay.py +412 -0
- flextool/process_outputs/union_realized_slice.py +224 -0
- flextool/process_outputs/write_outputs.py +1286 -0
- flextool/process_outputs/write_spinedb.py +1267 -0
- flextool/representative_periods/__init__.py +5 -0
- flextool/representative_periods/clustering.py +165 -0
- flextool/representative_periods/force_include.py +563 -0
- flextool/representative_periods/netload.py +365 -0
- flextool/representative_periods/netload_inputs.py +345 -0
- flextool/representative_periods/netload_iterate.py +722 -0
- flextool/representative_periods/preprocess.py +948 -0
- flextool/representative_periods/scenario_stack.py +195 -0
- flextool/representative_periods/weights.py +124 -0
- flextool/scenario_comparison/__init__.py +13 -0
- flextool/scenario_comparison/config_builder.py +158 -0
- flextool/scenario_comparison/constants.py +20 -0
- flextool/scenario_comparison/data_models.py +222 -0
- flextool/scenario_comparison/db_reader.py +399 -0
- flextool/scenario_comparison/dispatch_data.py +1002 -0
- flextool/scenario_comparison/dispatch_mappings.py +205 -0
- flextool/scenario_comparison/dispatch_plots.py +691 -0
- flextool/scenario_comparison/input_entity_colors.py +319 -0
- flextool/scenario_comparison/orchestrator.py +453 -0
- flextool/scenario_comparison/plan_union.py +244 -0
- flextool/scenario_comparison/plot_settings_seed.py +205 -0
- flextool/schemas/AXIS_CONTRACT.md +71 -0
- flextool/schemas/canonical_databases/howto_aggregate_output.json +6225 -0
- flextool/schemas/canonical_databases/howto_connections.json +5606 -0
- flextool/schemas/canonical_databases/howto_demand.json +5518 -0
- flextool/schemas/canonical_databases/howto_hydro_reservoir.json +6239 -0
- flextool/schemas/canonical_databases/howto_hydro_reservoir_with_pump.json +5933 -0
- flextool/schemas/canonical_databases/howto_non_sync_and_curtailment.json +5794 -0
- flextool/schemas/canonical_databases/howto_ramp_and_start_up.json +5707 -0
- flextool/schemas/canonical_databases/howto_stochastics.json +6032 -0
- flextool/schemas/canonical_databases/templates_examples.json +13532 -0
- flextool/schemas/canonical_databases/templates_time_settings_only.json +5340 -0
- flextool/schemas/comparison_settings_template.json +197 -0
- flextool/schemas/default_plot_settings.yaml +260 -0
- flextool/schemas/default_plots.yaml +2293 -0
- flextool/schemas/flextool_axis_contract.json +303 -0
- flextool/schemas/flextool_axis_contract.schema.json +247 -0
- flextool/schemas/old_flextool_import_template.json +4443 -0
- flextool/schemas/output_info_template.json +48 -0
- flextool/schemas/output_settings_template.json +256 -0
- flextool/schemas/pre_v26/flextool_template_constant_default.json +2105 -0
- flextool/schemas/pre_v26/flextool_template_default_optional_output.json +2152 -0
- flextool/schemas/pre_v26/flextool_template_default_value.json +2094 -0
- flextool/schemas/pre_v26/flextool_template_drop_down.json +2080 -0
- flextool/schemas/pre_v26/flextool_template_lifetime_method.json +1990 -0
- flextool/schemas/pre_v26/flextool_template_optional_outputs.json +2094 -0
- flextool/schemas/pre_v26/flextool_template_output_node_flows.json +2105 -0
- flextool/schemas/pre_v26/flextool_template_results_master.json +493 -0
- flextool/schemas/pre_v26/flextool_template_rolling_start_remove.json +2087 -0
- flextool/schemas/pre_v26/flextool_template_rolling_window.json +2059 -0
- flextool/schemas/pre_v26/flextool_template_storage_binding_defaults.json +46 -0
- flextool/schemas/pre_v26/flextool_template_v2.json +1990 -0
- flextool/schemas/pre_v26/flextool_template_v25.json +3864 -0
- flextool/schemas/spinedb_results_schema.json +581 -0
- flextool/schemas/spinedb_schema.json +4636 -0
- flextool/solver_config/copt.opt.template +18 -0
- flextool/solver_config/cplex.opt.template +25 -0
- flextool/solver_config/gurobi.opt.template +18 -0
- flextool/solver_config/highs.opt.template +18 -0
- flextool/solver_config/xpress.opt.template +26 -0
- flextool/spinedb_backend/__init__.py +26 -0
- flextool/spinedb_backend/_axis_enums.py +1119 -0
- flextool/spinedb_backend/_backend.py +1139 -0
- flextool/update_flextool/__init__.py +12 -0
- flextool/update_flextool/canonical_databases.py +251 -0
- flextool/update_flextool/db_migration.py +7108 -0
- flextool/update_flextool/ensure_settings_db.py +138 -0
- flextool/update_flextool/export_database.py +103 -0
- flextool/update_flextool/extend_tests_fixture.py +772 -0
- flextool/update_flextool/generate_canonical.py +274 -0
- flextool/update_flextool/initialize_database.py +42 -0
- flextool/update_flextool/install_info.py +225 -0
- flextool/update_flextool/self_update.py +464 -0
- flextool/update_flextool/sync_master_json_template.py +125 -0
- flextool/update_flextool/test_fixtures.py +187 -0
- flextool-4.0.0.dist-info/METADATA +217 -0
- flextool-4.0.0.dist-info/RECORD +322 -0
- flextool-4.0.0.dist-info/WHEEL +5 -0
- flextool-4.0.0.dist-info/entry_points.txt +17 -0
- flextool-4.0.0.dist-info/licenses/LICENSE.txt +19 -0
- flextool-4.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""Round-trip every tests/fixtures/*.json through the current schema migration.
|
|
2
|
+
|
|
3
|
+
Mirrors :mod:`flextool.update_flextool.canonical_databases` for the test
|
|
4
|
+
fixture corpus. The format used here differs from canonical_databases
|
|
5
|
+
(base64-packed values vs. UTF-8 decoded), so this module uses
|
|
6
|
+
``tests.db_utils.json_to_db`` / ``tests.db_utils.db_to_json`` rather than
|
|
7
|
+
the canonical ``initialize_database`` / ``export_database`` pair.
|
|
8
|
+
|
|
9
|
+
Run after a schema bump alongside ``sync_master_json_template`` and
|
|
10
|
+
``canonical_databases migrate-all``. See CONTRIBUTING.md.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python -m flextool.update_flextool.test_fixtures migrate-all
|
|
14
|
+
python -m flextool.update_flextool.test_fixtures verify
|
|
15
|
+
|
|
16
|
+
The ``verify`` subcommand is intended for CI: it performs the same
|
|
17
|
+
round-trip in a temp file and exits non-zero (printing a short diff
|
|
18
|
+
summary) when any committed fixture is out of sync with the current
|
|
19
|
+
schema.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import json
|
|
26
|
+
import shutil
|
|
27
|
+
import tempfile
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
from flextool.update_flextool.db_migration import migrate_database
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Resolved at runtime against the repository checkout — these fixtures live
|
|
34
|
+
# under ``tests/fixtures/`` (outside the installed wheel), so we walk up
|
|
35
|
+
# from this module to find the source tree.
|
|
36
|
+
TEST_FIXTURES: tuple[str, ...] = (
|
|
37
|
+
"tests.json",
|
|
38
|
+
"stochastics.json",
|
|
39
|
+
"lh2_three_region.json",
|
|
40
|
+
"h2_trade_parity.json",
|
|
41
|
+
"stochastics_pbt_inflow.json",
|
|
42
|
+
"branch2_parent_period.json",
|
|
43
|
+
"case14_dc_power_flow.json",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _fixtures_dir() -> Path:
|
|
48
|
+
"""Locate ``tests/fixtures/`` from a source checkout.
|
|
49
|
+
|
|
50
|
+
Walks up from this file (``flextool/update_flextool/test_fixtures.py``)
|
|
51
|
+
to the repo root and joins ``tests/fixtures``. Fails loudly if the
|
|
52
|
+
directory is missing — this module is only meaningful in an editable
|
|
53
|
+
install where the fixtures are present on disk.
|
|
54
|
+
"""
|
|
55
|
+
here = Path(__file__).resolve()
|
|
56
|
+
# .../flextool-engine/flextool/update_flextool/test_fixtures.py
|
|
57
|
+
repo_root = here.parent.parent.parent
|
|
58
|
+
fixtures = repo_root / "tests" / "fixtures"
|
|
59
|
+
if not fixtures.is_dir():
|
|
60
|
+
raise RuntimeError(
|
|
61
|
+
f"tests/fixtures/ not found at {fixtures}. "
|
|
62
|
+
"This migration must be run from a source checkout."
|
|
63
|
+
)
|
|
64
|
+
return fixtures
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _migrate_one(json_path: Path, out_path: Path) -> None:
|
|
68
|
+
"""Round-trip a single fixture: JSON -> SQLite -> migrate -> JSON.
|
|
69
|
+
|
|
70
|
+
Uses ``tests.db_utils.json_to_db`` and ``tests.db_utils.db_to_json``
|
|
71
|
+
so the base64 value-packing convention used by the test fixtures is
|
|
72
|
+
preserved across the round-trip.
|
|
73
|
+
"""
|
|
74
|
+
# Imported lazily so this module can be loaded outside a checkout
|
|
75
|
+
# (e.g. the canonical_databases command in a wheel install) without
|
|
76
|
+
# tripping over the test-package layering inversion.
|
|
77
|
+
from tests.db_utils import db_to_json, json_to_db
|
|
78
|
+
|
|
79
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
80
|
+
sqlite_path = Path(tmp) / "staging.sqlite"
|
|
81
|
+
url = json_to_db(json_path, sqlite_path)
|
|
82
|
+
migrate_database(url)
|
|
83
|
+
db_to_json(sqlite_path, out_path)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def migrate_all() -> None:
|
|
87
|
+
"""Migrate every ``tests/fixtures/*.json`` file in place.
|
|
88
|
+
|
|
89
|
+
Writes the result back over the source JSON. Diffs may be large
|
|
90
|
+
when a fixture's ``parameter_definitions`` are catching up to a new
|
|
91
|
+
schema; that is expected.
|
|
92
|
+
"""
|
|
93
|
+
fixtures = _fixtures_dir()
|
|
94
|
+
for name in TEST_FIXTURES:
|
|
95
|
+
src = fixtures / name
|
|
96
|
+
if not src.is_file():
|
|
97
|
+
print(f"!! test fixture missing: {src}")
|
|
98
|
+
continue
|
|
99
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
100
|
+
staging_json = Path(tmp) / name
|
|
101
|
+
_migrate_one(src, staging_json)
|
|
102
|
+
shutil.copyfile(staging_json, src)
|
|
103
|
+
print(f"migrated test fixture: {name}")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _summarise_diff(committed: Path, regenerated: Path) -> str:
|
|
107
|
+
"""Return a short human-readable summary of which top-level sections
|
|
108
|
+
differ between two fixture JSONs.
|
|
109
|
+
|
|
110
|
+
Used by ``verify`` to surface drift without flooding the CI log.
|
|
111
|
+
"""
|
|
112
|
+
with open(committed) as f:
|
|
113
|
+
a = json.load(f)
|
|
114
|
+
with open(regenerated) as f:
|
|
115
|
+
b = json.load(f)
|
|
116
|
+
keys = sorted(set(a) | set(b))
|
|
117
|
+
lines = []
|
|
118
|
+
for key in keys:
|
|
119
|
+
av = a.get(key)
|
|
120
|
+
bv = b.get(key)
|
|
121
|
+
if av == bv:
|
|
122
|
+
continue
|
|
123
|
+
la = len(av) if isinstance(av, list) else "?"
|
|
124
|
+
lb = len(bv) if isinstance(bv, list) else "?"
|
|
125
|
+
lines.append(f" {key}: committed={la} regenerated={lb}")
|
|
126
|
+
return "\n".join(lines) if lines else " (no top-level section differs — check value-level)"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def verify_all() -> int:
|
|
130
|
+
"""Verify that every committed fixture matches its migrated form.
|
|
131
|
+
|
|
132
|
+
Returns 0 when every file is byte-stable through the round-trip, or
|
|
133
|
+
a positive count of mismatched files otherwise. Intended for CI use
|
|
134
|
+
via ``python -m flextool.update_flextool.test_fixtures verify``.
|
|
135
|
+
"""
|
|
136
|
+
fixtures = _fixtures_dir()
|
|
137
|
+
mismatches = 0
|
|
138
|
+
for name in TEST_FIXTURES:
|
|
139
|
+
src = fixtures / name
|
|
140
|
+
if not src.is_file():
|
|
141
|
+
print(f"!! test fixture missing: {src}")
|
|
142
|
+
mismatches += 1
|
|
143
|
+
continue
|
|
144
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
145
|
+
regenerated = Path(tmp) / name
|
|
146
|
+
_migrate_one(src, regenerated)
|
|
147
|
+
with open(src) as f:
|
|
148
|
+
committed_text = f.read()
|
|
149
|
+
with open(regenerated) as f:
|
|
150
|
+
regenerated_text = f.read()
|
|
151
|
+
if committed_text == regenerated_text:
|
|
152
|
+
print(f"ok: {name}")
|
|
153
|
+
else:
|
|
154
|
+
mismatches += 1
|
|
155
|
+
print(f"DRIFT: {name}")
|
|
156
|
+
print(_summarise_diff(src, regenerated))
|
|
157
|
+
if mismatches:
|
|
158
|
+
print(
|
|
159
|
+
f"\n{mismatches} test fixture(s) out of sync with current schema. "
|
|
160
|
+
"Run `python -m flextool.update_flextool.test_fixtures migrate-all`."
|
|
161
|
+
)
|
|
162
|
+
return mismatches
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def main(argv: list[str] | None = None) -> int:
|
|
166
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
167
|
+
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
168
|
+
sub.add_parser(
|
|
169
|
+
"migrate-all",
|
|
170
|
+
help="Round-trip every tests/fixtures/*.json through the current schema",
|
|
171
|
+
)
|
|
172
|
+
sub.add_parser(
|
|
173
|
+
"verify",
|
|
174
|
+
help="Check every test fixture is byte-stable through the current schema",
|
|
175
|
+
)
|
|
176
|
+
args = parser.parse_args(argv)
|
|
177
|
+
|
|
178
|
+
if args.cmd == "migrate-all":
|
|
179
|
+
migrate_all()
|
|
180
|
+
return 0
|
|
181
|
+
elif args.cmd == "verify":
|
|
182
|
+
return verify_all()
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
if __name__ == "__main__":
|
|
187
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flextool
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: IRENA FlexTool is an energy and power systems model for understanding the role of variable power generation in future energy systems.
|
|
5
|
+
Author: IRENA FlexTool contributors
|
|
6
|
+
License: © International Renewable Energy Agency 2018-2022
|
|
7
|
+
|
|
8
|
+
The FlexTool is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
|
|
9
|
+
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
The FlexTool is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
12
|
+
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Lesser General Public License along with the FlexTool.
|
|
15
|
+
If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Author: Juha Kiviluoma (2017-2022), VTT Technical Research Centre of Finland
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
-----------------------------------------------
|
|
23
|
+
IRENA FlexTool uses the HiGHS solver, which has its own license.
|
|
24
|
+
HiGHS is licensed with MIT license. Please see https://github.com/ERGO-Code/HiGHS for more information.
|
|
25
|
+
Project-URL: Documentation, https://irena-flextool.github.io/flextool/
|
|
26
|
+
Project-URL: Repository, https://github.com/irena-flextool/flextool
|
|
27
|
+
Project-URL: Issues, https://github.com/irena-flextool/flextool/issues
|
|
28
|
+
Keywords: energy-systems,optimization,linear-programming,mixed-integer-programming,power-systems,investment-planning,highs,spine
|
|
29
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
30
|
+
Classifier: Intended Audience :: Science/Research
|
|
31
|
+
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
37
|
+
Classifier: Topic :: Scientific/Engineering
|
|
38
|
+
Requires-Python: >=3.11
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
License-File: LICENSE.txt
|
|
41
|
+
Requires-Dist: polar-high>=3.7.0
|
|
42
|
+
Requires-Dist: highspy<=1.14.0
|
|
43
|
+
Requires-Dist: polars>=1.40
|
|
44
|
+
Requires-Dist: pandas
|
|
45
|
+
Requires-Dist: spinedb-api
|
|
46
|
+
Requires-Dist: openpyxl
|
|
47
|
+
Requires-Dist: odfpy
|
|
48
|
+
Requires-Dist: python-calamine
|
|
49
|
+
Requires-Dist: xlsxwriter
|
|
50
|
+
Requires-Dist: pyyaml
|
|
51
|
+
Requires-Dist: matplotlib
|
|
52
|
+
Requires-Dist: psutil
|
|
53
|
+
Requires-Dist: sv-ttk
|
|
54
|
+
Requires-Dist: screeninfo
|
|
55
|
+
Requires-Dist: pywin32; sys_platform == "win32"
|
|
56
|
+
Provides-Extra: toolbox
|
|
57
|
+
Requires-Dist: spinetoolbox; extra == "toolbox"
|
|
58
|
+
Provides-Extra: viewer
|
|
59
|
+
Requires-Dist: tsdownsample>=0.1.3; extra == "viewer"
|
|
60
|
+
Requires-Dist: networkx>=3.0; extra == "viewer"
|
|
61
|
+
Provides-Extra: engine-polars
|
|
62
|
+
Provides-Extra: dev
|
|
63
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
64
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
|
|
65
|
+
Requires-Dist: pytest-xdist>=3.0; extra == "dev"
|
|
66
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
67
|
+
Dynamic: license-file
|
|
68
|
+
|
|
69
|
+
[](https://pypi.org/project/flextool/)
|
|
70
|
+
[](https://irena-flextool.github.io/flextool/)
|
|
71
|
+
[](https://www.python.org/downloads/release/python-3120/)
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
IRENA FlexTool is an energy and power systems model for understanding the role of variable power generation in future energy systems. It performs capacity expansion planning as well as operational planning.
|
|
76
|
+
|
|
77
|
+
> [!NOTE]
|
|
78
|
+
> The previous `master` branch is deprecated and no longer updated — `main` is
|
|
79
|
+
> now FlexTool. If you still run FlexTool from `master`, migrate with a fresh
|
|
80
|
+
> parallel install (separate directory and venv); see
|
|
81
|
+
> [Installation](#installation) so your existing setup is left untouched.
|
|
82
|
+
|
|
83
|
+
## What's new
|
|
84
|
+
|
|
85
|
+
- **A lot faster.** The model build and pre-processing now run as pure Python
|
|
86
|
+
instead of the previous GLPSOL-based text pre-processing and AMPL-style model
|
|
87
|
+
translation. There is no LP file written to disk and re-read between build and
|
|
88
|
+
solve.
|
|
89
|
+
- **Automatic problem scaling.** The `polar-high` matrix layer automatically
|
|
90
|
+
scales the optimisation problem before it reaches the solver. Better numerical
|
|
91
|
+
conditioning often speeds up the HiGHS solve considerably — sometimes
|
|
92
|
+
dramatically — so total run time usually improves well beyond the faster build
|
|
93
|
+
alone. The solver is still HiGHS; the gain comes from handing it a
|
|
94
|
+
better-conditioned problem.
|
|
95
|
+
- **A new, easy-to-use interface.** The **FlexTool GUI** is a standalone
|
|
96
|
+
application (`python -m flextool.gui`) that manages projects and input
|
|
97
|
+
sources, runs scenarios, and lets you **browse the results** — a result viewer
|
|
98
|
+
reads outputs directly and supports single-scenario, scenario-comparison, and
|
|
99
|
+
network-graph views with keyboard navigation. See the
|
|
100
|
+
[FlexTool GUI guide](https://irena-flextool.github.io/flextool/flextool_gui_interface/).
|
|
101
|
+
- **Spine Toolbox is still a parallel interface.** Advanced users who build
|
|
102
|
+
multi-tool workflows or integrate FlexTool with other models can keep using
|
|
103
|
+
the [Spine Toolbox workflow](https://irena-flextool.github.io/flextool/spine_toolbox/).
|
|
104
|
+
- **The same model and data.** Existing input databases continue to work; the
|
|
105
|
+
change is in how the matrix is generated and solved, not in the model
|
|
106
|
+
formulation.
|
|
107
|
+
|
|
108
|
+
This is IRENA FlexTool v4 (see the current version in CHANGELOG.md). Report any bugs or difficulties in the [issue tracker](https://github.com/irena-flextool/flextool/issues).
|
|
109
|
+
The previous version of IRENA FlexTool can be found in https://www.irena.org/energytransition/Energy-System-Models-and-Data/IRENA-FlexTool.
|
|
110
|
+
|
|
111
|
+
## Under the hood: Rust-based matrix generation
|
|
112
|
+
|
|
113
|
+
FlexTool is a thin Python layer over a Rust engine. It reads its input data and
|
|
114
|
+
builds the optimisation matrix as [polars](https://pola.rs/) DataFrames via
|
|
115
|
+
[`polar-high`](https://github.com/nodal-tools/polar-high), then solves with
|
|
116
|
+
[HiGHS](https://highs.dev/). Variables and parameters are polars frames, so
|
|
117
|
+
multiplications become joins and aggregations become group-bys — the heavy
|
|
118
|
+
coefficient work runs inside polars' Rust core rather than as per-coefficient
|
|
119
|
+
Python objects, and the matrix goes straight to HiGHS through `highspy` with no
|
|
120
|
+
intermediate LP/MPS file. `polar-high` is a general-purpose, domain-free
|
|
121
|
+
modelling layer published separately (Apache-2.0, `pip install polar-high`); it
|
|
122
|
+
also applies the automatic problem scaling noted above, and its
|
|
123
|
+
[benchmark](https://nodal-tools.fi/polar-high/compare/benchmark/) compares it
|
|
124
|
+
against linopy and Pyomo on the same HiGHS solver.
|
|
125
|
+
|
|
126
|
+
## Installation
|
|
127
|
+
|
|
128
|
+
### Check your Python (and possibly install it)
|
|
129
|
+
|
|
130
|
+
FlexTool requires **Python 3.11+**.
|
|
131
|
+
|
|
132
|
+
Open a terminal (Windows: Command Prompt or PowerShell; macOS: Terminal; Linux: your shell)
|
|
133
|
+
and check which Python you have:
|
|
134
|
+
|
|
135
|
+
| Platform | Command |
|
|
136
|
+
|---|---|
|
|
137
|
+
| Windows | `py --version` (falls back to `python --version`) |
|
|
138
|
+
| macOS / Linux | `python3 --version` |
|
|
139
|
+
|
|
140
|
+
The output looks like `Python 3.12.4`. If the command is not found, prints
|
|
141
|
+
something below 3.11, or (on Windows) opens the Microsoft Store, install Python
|
|
142
|
+
from https://www.python.org/downloads/ — on Windows tick
|
|
143
|
+
**"Add python.exe to PATH"** in the installer. Then close and reopen the
|
|
144
|
+
terminal so the new PATH takes effect.
|
|
145
|
+
|
|
146
|
+
> On Windows, use `py` in place of `python` in the commands below if `python`
|
|
147
|
+
> is not recognised. If several versions are installed, `py -3.11 --version`
|
|
148
|
+
> (or `-3.12`, …) picks a specific one, and `py -0` lists them all.
|
|
149
|
+
> On macOS/Linux, `python` often means Python 2 or does not exist at all, so
|
|
150
|
+
> use `python3`. Inside an activated virtual environment, plain `python` always
|
|
151
|
+
> means that environment's Python on every platform.
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### Install from PyPI (recommended)
|
|
155
|
+
|
|
156
|
+
Install FlexTool into a virtual environment to keep its packages separate from
|
|
157
|
+
other Python applications. If you want to install into the base Python (perhaps
|
|
158
|
+
because you do not otherwise use Python), just run the last command from below,
|
|
159
|
+
`pip install flextool`.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
python -m venv .venv # Windows: py -m venv .venv
|
|
163
|
+
# macOS/Linux: python3 -m venv .venv
|
|
164
|
+
# activate — Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
165
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
166
|
+
# Linux / macOS: . .venv/bin/activate
|
|
167
|
+
python -m pip install --upgrade pip
|
|
168
|
+
pip install flextool
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Your prompt should now show `(.venv)`. Verify with `python --version` — it
|
|
172
|
+
should report 3.11 or newer.
|
|
173
|
+
|
|
174
|
+
(If PowerShell blocks the activate script, run once per user:
|
|
175
|
+
`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`.)
|
|
176
|
+
|
|
177
|
+
Launch the FlexTool GUI:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
flextool
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
— equivalently `python -m flextool.gui`. The GUI creates and manages your
|
|
184
|
+
projects and input databases; to seed the bundled template and example
|
|
185
|
+
databases (handy for the CLI or Spine Toolbox workflows) run `flextool-update`.
|
|
186
|
+
|
|
187
|
+
### Install from source (developers / latest `main`)
|
|
188
|
+
|
|
189
|
+
To participate in FlexTool development — or to run the not-yet-released `main`
|
|
190
|
+
— clone the repo and install it editable:
|
|
191
|
+
|
|
192
|
+
```powershell
|
|
193
|
+
git clone https://github.com/irena-flextool/flextool.git
|
|
194
|
+
cd flextool
|
|
195
|
+
python -m venv .venv
|
|
196
|
+
.\.venv\Scripts\Activate.ps1 # Linux / macOS: . .venv/bin/activate
|
|
197
|
+
python -m pip install --upgrade pip
|
|
198
|
+
pip install -e .
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The editable install picks up source changes on `git pull`; re-run
|
|
202
|
+
`pip install -e .` only when a dependency pin in `pyproject.toml` changes.
|
|
203
|
+
|
|
204
|
+
### Update FlexTool:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
# If using virtual environment (venv), then activate venv first:
|
|
208
|
+
# Windows PowerShell: .\.venv\Scripts\Activate.ps1
|
|
209
|
+
# Windows CMD: .\.venv\Scripts\activate.bat
|
|
210
|
+
# Linux / macOS: . .venv/bin/activate
|
|
211
|
+
pip install --upgrade flextool
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## [Documentation](https://irena-flextool.github.io/flextool/) and [installation](https://irena-flextool.github.io/flextool/install_toolbox/)
|
|
215
|
+
|
|
216
|
+
> [!IMPORTANT]
|
|
217
|
+
> Installation, user guide and ***documentation*** can be found at: https://irena-flextool.github.io/flextool/.
|