Source code for otoole.convert

"""This module implements the public API of the otoole package

Use the otoole ``convert`` function to convert between different file formats.
Import the convert function from the otoole package::

>>> from otoole import convert
>>> convert('config.yaml', 'excel', 'datafile', 'input.xlsx', 'output.dat')

"""

import logging
import os
from typing import Dict, Optional, Tuple, Union

import pandas as pd

from otoole.exceptions import OtooleError
from otoole.input import Context, ReadStrategy, WriteStrategy
from otoole.read_strategies import ReadCsv, ReadDatafile, ReadExcel
from otoole.results.results import ReadCbc, ReadCplex, ReadGlpk, ReadGurobi, ReadResults
from otoole.utils import _read_file, read_deprecated_datapackage, validate_config
from otoole.write_strategies import WriteCsv, WriteDatafile, WriteExcel

logger = logging.getLogger(__name__)


[docs]def read_results( config: str, from_format: str, from_path: str, input_format: str, input_path: str, glpk_model: Optional[str] = None, ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, float]]: """Read OSeMOSYS results from CBC, GLPK, Gurobi, or CPLEX results files Arguments --------- config : str Path to config file from_format : str Available options are 'cbc', 'gurobi', 'cplex', and 'glpk' from_path : str Path to source file (if datafile or excel) or folder (csv) input_format: str Format of input data. Available options are 'datafile', 'csv' and 'excel' input_path: str Path to input data glpk_model : str Path to ``*.glp`` model file Returns ------- Tuple[dict[str, pd.DataFrame], dict[str, float]] Dictionary of parameter and set data and dictionary of default values """ user_config = _get_user_config(config) input_strategy = _get_read_strategy(user_config, input_format) result_strategy = _get_read_result_strategy(user_config, from_format, glpk_model) if input_strategy: input_data, _ = input_strategy.read(input_path) else: input_data = {} if result_strategy: results, default_values = result_strategy.read(from_path, input_data=input_data) return results, default_values else: msg = "Conversion from {} is not yet implemented".format(from_format) raise NotImplementedError(msg)
[docs]def convert_results( config: str, from_format: str, to_format: str, from_path: str, to_path: str, input_format: str, input_path: str, write_defaults: bool = False, glpk_model: Optional[str] = None, ) -> bool: """Post-process results from a CBC, CPLEX, Gurobi, or GLPK solution file into CSV format Arguments --------- config : str Path to config file from_format : str Available options are 'cbc', 'cplex' and 'gurobi' to_format : str Available options are 'csv' from_path : str Path to cbc, cplex or gurobi solution file to_path : str Path to destination folder input_format: str Format of input data. Available options are 'datafile', 'csv' and 'excel' input_path: str Path to input data write_defaults : bool Write default values to CSVs glpk_model : str Path to ``*.glp`` model file Returns ------- bool True if conversion was successful, False otherwise """ msg = "Conversion from {} to {} is not yet implemented".format( from_format, to_format ) user_config = _get_user_config(config) # set read strategy read_strategy = _get_read_result_strategy(user_config, from_format, glpk_model) # set write strategy write_defaults = True if write_defaults else False if to_format == "csv": write_strategy = WriteCsv( user_config=user_config, write_defaults=write_defaults ) else: raise NotImplementedError(msg) # read in input file input_data, _ = read(config, input_format, input_path) if read_strategy and write_strategy: context = Context(read_strategy, write_strategy) context.convert(from_path, to_path, input_data=input_data) else: raise NotImplementedError(msg) return True
def _get_read_result_strategy( user_config, from_format, glpk_model=None ) -> Union[ReadResults, None]: """Get ``ReadResults`` for gurobi, cbc, cplex, and glpk formats Arguments --------- config : dict User configuration describing parameters and sets from_format : str Available options are 'cbc', 'gurobi', 'cplex', and 'glpk' glpk_model : str Path to ``*.glp`` model file Returns ------- ReadStrategy or None A ReadStrategy object. Returns None if from_format is not recognised """ if from_format == "cbc": read_strategy: ReadResults = ReadCbc(user_config) elif from_format == "gurobi": read_strategy = ReadGurobi(user_config=user_config) elif from_format == "cplex": read_strategy = ReadCplex(user_config=user_config) elif from_format == "glpk": if not glpk_model: raise OtooleError(resource="Read GLPK", message="Provide glpk model file") read_strategy = ReadGlpk(user_config=user_config, glpk_model=glpk_model) else: return None return read_strategy def _get_user_config(config) -> dict: """Read in the configuration file Arguments --------- config : str Path to config file Returns ------- dict A dictionary containing the user configuration """ if config: _, ending = os.path.splitext(config) with open(config, "r") as config_file: user_config = _read_file(config_file, ending) logger.info("Reading config from {}".format(config)) logger.info("Validating config from {}".format(config)) validate_config(user_config) return user_config def _get_read_strategy(user_config, from_format, keep_whitespace=False) -> ReadStrategy: """Get ``ReadStrategy`` for csv/datafile/excel format Arguments --------- config : dict User configuration describing parameters and sets from_format : str Available options are 'datafile', 'datapackage', 'csv' and 'excel' keep_whitespace: bool, default: False Keep whitespace in CSVs Returns ------- ReadStrategy or None A ReadStrategy object. Returns None if from_format is not recognised """ keep_whitespace = True if keep_whitespace else False if from_format == "datafile": read_strategy: ReadStrategy = ReadDatafile(user_config=user_config) elif from_format == "datapackage": logger.warning( "Reading from datapackage is deprecated, trying to read from CSVs" ) logger.info("Successfully read folder of CSVs") read_strategy = ReadCsv( user_config=user_config, keep_whitespace=keep_whitespace ) # typing: ReadStrategy elif from_format == "csv": read_strategy = ReadCsv( user_config=user_config, keep_whitespace=keep_whitespace ) # typing: ReadStrategy elif from_format == "excel": read_strategy = ReadExcel( user_config=user_config, keep_whitespace=keep_whitespace ) # typing: ReadStrategy else: msg = f"Conversion from {from_format} is not supported" raise NotImplementedError(msg) return read_strategy def _get_write_strategy(user_config, to_format, write_defaults=False) -> WriteStrategy: """Get ``WriteStrategy`` for csv/datafile/excel format Arguments --------- user_config : dict User configuration describing parameters and sets to_format : str Available options are 'datafile', 'datapackage', 'csv' and 'excel' write_defaults: bool, default: False Write default values to output format Returns ------- WriteStrategy or None A ReadStrategy object. Returns None if to_format is not recognised """ # set write strategy write_defaults = True if write_defaults else False if to_format == "datapackage": write_strategy: WriteStrategy = WriteCsv( user_config=user_config, write_defaults=write_defaults ) elif to_format == "excel": write_strategy = WriteExcel( user_config=user_config, write_defaults=write_defaults ) elif to_format == "datafile": write_strategy = WriteDatafile( user_config=user_config, write_defaults=write_defaults ) elif to_format == "csv": write_strategy = WriteCsv( user_config=user_config, write_defaults=write_defaults ) else: msg = f"Conversion to {to_format} is not supported" raise NotImplementedError(msg) return write_strategy
[docs]def convert( config, from_format, to_format, from_path, to_path, write_defaults=False, keep_whitespace=False, ) -> bool: """Convert OSeMOSYS data from/to datafile, csv and Excel formats Arguments --------- config : str Path to config file from_format : str Available options are 'datafile', 'datapackage', 'csv' and 'excel' to_format : str Available options are 'datafile', 'datapackage', 'csv' and 'excel' from_path : str Path to destination file (if datafile or excel) or folder (csv or datapackage) write_defaults: bool, default: False Write default values to CSVs keep_whitespace: bool, default: False Keep whitespace in CSVs Returns ------- bool True if conversion was successful, False otherwise """ user_config = _get_user_config(config) read_strategy = _get_read_strategy( user_config, from_format, keep_whitespace=keep_whitespace ) write_strategy = _get_write_strategy( user_config, to_format, write_defaults=write_defaults ) if from_format == "datapackage": logger.warning( "Reading from and writing to datapackage is deprecated, writing to CSVs" ) from_path = read_deprecated_datapackage(from_path) to_path = os.path.join(os.path.dirname(to_path), "data") context = Context(read_strategy, write_strategy) context.convert(from_path, to_path) return True
[docs]def read( config: str, from_format: str, from_path: str, keep_whitespace: bool = False ) -> Tuple[Dict[str, pd.DataFrame], Dict[str, float]]: """Read OSeMOSYS data from datafile, csv or Excel formats Arguments --------- config : str Path to config file from_format : str Available options are 'datafile', 'csv', 'excel' and 'datapackage' [deprecated] from_path : str Path to source file (if datafile or excel) or folder (csv) keep_whitespace: bool, default: False Keep whitespace in source files Returns ------- Tuple[dict[str, pd.DataFrame], dict[str, float]] Dictionary of parameter and set data and dictionary of default values """ user_config = _get_user_config(config) read_strategy = _get_read_strategy( user_config, from_format, keep_whitespace=keep_whitespace ) if from_format == "datapackage": from_path = read_deprecated_datapackage(from_path) return read_strategy.read(from_path)
[docs]def write( config: str, to_format: str, to_path: str, inputs, default_values: Optional[Dict[str, float]] = None, ) -> bool: """Write OSeMOSYS data to datafile, csv or Excel formats Arguments --------- config : str Path to config file to_format : str Available options are 'datafile', 'csv', 'excel' and 'datapackage' [deprecated], to_path : str Path to destination file (if datafile or excel) or folder (csv)) inputs : dict[str, pd.DataFrame] Dictionary of pandas data frames to write default_values: dict[str, float], default: None Dictionary of default values to write to datafile """ user_config = _get_user_config(config) if default_values is None: write_strategy = _get_write_strategy( user_config, to_format, write_defaults=False ) write_strategy.write(inputs, to_path, {}) else: write_strategy = _get_write_strategy( user_config, to_format, write_defaults=True ) write_strategy.write(inputs, to_path, default_values) return True