diff --git a/docs/tables/get_functions.tab b/docs/tables/get_functions.tab index 996f490b..3cb138e8 100644 --- a/docs/tables/get_functions.tab +++ b/docs/tables/get_functions.tab @@ -1,9 +1,9 @@ Vensim Vensim example Xmile Xmile example Abstract Syntax Python Translation Vensim comments Xmile comments Python comments -GET XLS DATA "GET XLS DATA('file', 'sheet', 'time_row_or_col', 'cell')" "GetDataStructure('file', 'sheet', 'time_row_or_col', 'cell')" pysd.external.ExtData(...) -GET DIRECT DATA "GET DIRECT DATA('file', 'sheet', 'time_row_or_col', 'cell')" "GetDataStructure('file', 'sheet', 'time_row_or_col', 'cell')" pysd.external.ExtData(...) -GET XLS LOOKUPS "GET XLS LOOKUPS('file', 'sheet', 'x_row_or_col', 'cell')" "GetLookupsStructure('file', 'sheet', 'x_row_or_col', 'cell')" pysd.external.ExtLookup(...) -GET DIRECT LOOKUPS "GET DIRECT LOOKUPS('file', 'sheet', 'x_row_or_col', 'cell')" "GetLookupsStructure('file', 'sheet', 'x_row_or_col', 'cell')" pysd.external.ExtLookup(...) -GET XLS CONSTANTS "GET XLS CONSTANTS('file', 'sheet', 'cell')" "GetConstantsStructure('file', 'sheet', 'cell')" pysd.external.ExtConstant(...) -GET DIRECT CONSTANTS "GET DIRECT CONSTANTS('file', 'sheet', 'cell')" "GetConstantsStructure('file', 'sheet', 'cell')" pysd.external.ExtConstant(...) -GET XLS SUBSCRIPT "GET XLS SUBSCRIPT('file', 'sheet', 'first_cell', 'last_cell', 'prefix')" pysd.external.ExtSubscript(...) -GET DIRECT SUBSCRIPT "GET DIRECT SUBSCRIPT('file', 'sheet', 'first_cell', 'last_cell', 'prefix')" pysd.external.ExtSubscript(...) +GET XLS DATA "GET XLS DATA('file', 'tab', 'time_row_or_col', 'cell')" "GetDataStructure('file', 'tab', 'time_row_or_col', 'cell')" pysd.external.ExtData(...) +GET DIRECT DATA "GET DIRECT DATA('file', 'tab', 'time_row_or_col', 'cell')" "GetDataStructure('file', 'tab', 'time_row_or_col', 'cell')" pysd.external.ExtData(...) +GET XLS LOOKUPS "GET XLS LOOKUPS('file', 'tab', 'x_row_or_col', 'cell')" "GetLookupsStructure('file', 'tab', 'x_row_or_col', 'cell')" pysd.external.ExtLookup(...) +GET DIRECT LOOKUPS "GET DIRECT LOOKUPS('file', 'tab', 'x_row_or_col', 'cell')" "GetLookupsStructure('file', 'tab', 'x_row_or_col', 'cell')" pysd.external.ExtLookup(...) +GET XLS CONSTANTS "GET XLS CONSTANTS('file', 'tab', 'cell')" "GetConstantsStructure('file', 'tab', 'cell')" pysd.external.ExtConstant(...) +GET DIRECT CONSTANTS "GET DIRECT CONSTANTS('file', 'tab', 'cell')" "GetConstantsStructure('file', 'tab', 'cell')" pysd.external.ExtConstant(...) +GET XLS SUBSCRIPT "GET XLS SUBSCRIPT('file', 'tab', 'first_cell', 'last_cell', 'prefix')" pysd.external.ExtSubscript(...) +GET DIRECT SUBSCRIPT "GET DIRECT SUBSCRIPT('file', 'tab', 'first_cell', 'last_cell', 'prefix')" pysd.external.ExtSubscript(...) diff --git a/docs/whats_new.rst b/docs/whats_new.rst index b61cf367..4a431a19 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -1,6 +1,6 @@ What's New ========== -v3.14.1 (2024/07/XX) +v3.14.1 (2024/07/18) -------------------- New Features ~~~~~~~~~~~~ @@ -15,8 +15,11 @@ Bug fixes ~~~~~~~~~ - Support for :py:mod:`numpy` 2. (`@enekomartinmartinez `_) - Allow multiple font styles in var names (:issue:`443`). (`@rogersamso `_) -- Allow Vensims GET DIRECT/XLS SUBSCRIPT when lastcell is not a cell value (:issue:`443`). (`@enekomartinmartinez `_) -- Allow Vensims GET DIRECT/XLS SUBSCRIPT defined with cell range names (:issue:`261`). (`@enekomartinmartinez `_) +- Allow Vensims GET DIRECT/XLS SUBSCRIPT when lastcell is not a cell value (:issue:`443`). (`@enekomartinmartinez `_) +- Allow Vensims GET DIRECT/XLS SUBSCRIPT defined with cell range names (:issue:`261`). (`@enekomartinmartinez `_) +- Translate filenames as raw :py:class:`str` to made them work properly for Windows paths (:issue:`443`). (`@enekomartinmartinez `_) +- Improve support for reading :py:class:`pysd.py_backend.external.External` from all the spreadsheet files includying those types from open software ('.odf', '.ods', '.odt'). (`@enekomartinmartinez `_) +- Improve support for reading :py:class:`pysd.py_backend.external.External` from CSV, TAB and any other kind of text file. (`@enekomartinmartinez `_) Documentation ~~~~~~~~~~~~~ @@ -28,6 +31,10 @@ Internal Changes ~~~~~~~~~~~~~~~~ - Fix CI tests. (`@rogersamso `_) - Run CI coverage only on ubuntu and lowest Python. (`@enekomartinmartinez `_) +- Rename 'sheet' by 'tab' in :py:class:`pysd.py_backend.external.External` and related functions and classes to follow Vensim's nomenclature. (`@enekomartinmartinez `_) +- Add error message when no subscripts are read from :py:class:`pysd.py_backend.external.ExtSubscript` during the model building. (`@enekomartinmartinez `_) +- Add error message when a :py:class:`pysd.py_backend.external.External` cell/firstcell is interpreted as cellrange name but the input file is not a spreadsheet. (`@enekomartinmartinez `_) +- Improve parsing of quoted arguments in the vensim translator for external lookups and external subscripts. (`@enekomartinmartinez `_) v3.14.0 (2024/04/24) -------------------- diff --git a/pysd/builders/python/python_expressions_builder.py b/pysd/builders/python/python_expressions_builder.py index b207d3b9..1d685a51 100644 --- a/pysd/builders/python/python_expressions_builder.py +++ b/pysd/builders/python/python_expressions_builder.py @@ -891,7 +891,7 @@ def build(self, arguments: dict) -> Union[BuildAST, None]: """ self.component.type = "Lookup" self.component.subtype = "External" - arguments["params"] = "'%s', '%s', '%s', '%s'" % ( + arguments["params"] = "r'%s', '%s', '%s', '%s'" % ( self.file, self.tab, self.x_row_or_col, self.cell ) final_subs, arguments["subscripts"] =\ @@ -966,7 +966,7 @@ def build(self, arguments: dict) -> Union[BuildAST, None]: """ self.component.type = "Data" self.component.subtype = "External" - arguments["params"] = "'%s', '%s', '%s', '%s'" % ( + arguments["params"] = "r'%s', '%s', '%s', '%s'" % ( self.file, self.tab, self.time_row_or_col, self.cell ) final_subs, arguments["subscripts"] =\ @@ -1041,7 +1041,7 @@ def build(self, arguments: dict) -> Union[BuildAST, None]: """ self.component.type = "Constant" self.component.subtype = "External" - arguments["params"] = "'%s', '%s', '%s'" % ( + arguments["params"] = "r'%s', '%s', '%s'" % ( self.file, self.tab, self.cell ) final_subs, arguments["subscripts"] =\ diff --git a/pysd/builders/python/subscripts.py b/pysd/builders/python/subscripts.py index 1ba8b4b2..51f0b321 100644 --- a/pysd/builders/python/subscripts.py +++ b/pysd/builders/python/subscripts.py @@ -59,11 +59,16 @@ def subscripts(self, abstract_subscripts: List[AbstractSubscriptRange]): # subscript from file self._subscripts[sub.name] = ExtSubscript( file_name=sub.subscripts["file"], - sheet=sub.subscripts["tab"], + tab=sub.subscripts["tab"], firstcell=sub.subscripts["firstcell"], lastcell=sub.subscripts["lastcell"], prefix=sub.subscripts["prefix"], root=self._root).subscript + + if not self._subscripts[sub.name]: + raise ValueError( + f"Subscript range '{sub.name}' empty:\n\t" + + str(sub.subscripts)) else: raise ValueError( f"Invalid definition of subscript '{sub.name}':\n\t" diff --git a/pysd/py_backend/external.py b/pysd/py_backend/external.py index 35e4ffae..5401d5f6 100644 --- a/pysd/py_backend/external.py +++ b/pysd/py_backend/external.py @@ -6,15 +6,22 @@ import re import warnings -import pandas as pd + +from openpyxl import load_workbook +from openpyxl.utils.exceptions import InvalidFileException + import numpy as np import xarray as xr -from openpyxl import load_workbook +import pandas as pd + from . import utils from .data import Data from .lookups import Lookups +_SPREADSHEET_EXTS = {'.xls', '.xlsx', '.xlsm', '.xlsb', '.odf', '.ods', '.odt'} + + class Excels(): """ Class to save the read Excel files and thus avoid double reading @@ -22,19 +29,35 @@ class Excels(): _Excels, _Excels_opyxl = {}, {} @classmethod - def read(cls, file_name, sheet_name): + def read(cls, file_name, tab): """ Read the Excel file or return the previously read one """ - if file_name.joinpath(sheet_name) in cls._Excels: - return cls._Excels[file_name.joinpath(sheet_name)] + if file_name.joinpath(tab) in cls._Excels: + return cls._Excels[file_name.joinpath(tab)] else: + # get the function to read the data based on its extension + read_kwargs = {} + ext = file_name.suffix.lower() + if ext in _SPREADSHEET_EXTS: + read_func = pd.read_excel + read_kwargs['sheet_name'] = tab + elif ext == '.csv': + read_func = pd.read_csv + if tab and not tab[0].isalnum(): + read_kwargs['sep'] = tab + else: + read_func = pd.read_table + if tab and not tab[0].isalnum(): + read_kwargs['sep'] = tab + # read the data excel = np.array([ pd.to_numeric(ex, errors='coerce') for ex in - pd.read_excel(file_name, sheet_name, header=None).values + read_func(file_name, header=None, **read_kwargs).values ]) - cls._Excels[file_name.joinpath(sheet_name)] = excel + # save data for future retrievals + cls._Excels[file_name.joinpath(tab)] = excel return excel @classmethod @@ -78,8 +101,9 @@ class External(object): fail, but it may be used to check the quality of the data. file: str File name from which the data is read. - sheet: str - Sheet name from which the data is read. + tab: str + Tab name from which the data is read. If file type is not a + spreadsheet this will be used as a separator. """ missing = "warning" @@ -87,7 +111,7 @@ class External(object): def __init__(self, py_name): self.py_name = py_name self.file = None - self.sheet = None + self.tab = None def __str__(self): return self.py_name @@ -109,34 +133,27 @@ def _get_data_from_file(self, rows, cols): depending on the shape of the requested data """ - ext = self.file.suffix.lower() - if ext in ['.xls', '.xlsx', '.xlsm']: - # read data - data = Excels.read( - self.file, - self.sheet)[rows[0]:rows[1], cols[0]:cols[1]].copy() + # read data + data = Excels.read( + self.file, + self.tab)[rows[0]:rows[1], cols[0]:cols[1]].copy() - shape = data.shape + shape = data.shape - # empty cells - if shape[0] == 0 or shape[1] == 0: - raise ValueError( - self.py_name + "\n" - "The cells are empty.\n" - + self._file_sheet - ) - - # if it is a single row remove its dimension - if shape[1] == 1: - data = data[:, 0] - if shape[0] == 1: - data = data[0] - return data + # empty cells + if shape[0] == 0 or shape[1] == 0: + raise ValueError( + self.py_name + "\n" + "The cells are empty.\n" + + self._file_sheet + ) - raise NotImplementedError( - self.py_name + "\n" - f"The files with extension {ext} are not implemented" - ) + # if it is a single row remove its dimension + if shape[1] == 1: + data = data[:, 0] + if shape[0] == 1: + data = data[0] + return data def _get_data_from_file_opyxl(self, cellname): """ @@ -156,13 +173,23 @@ def _get_data_from_file_opyxl(self, cellname): """ # read data - excel = Excels.read_opyxl(self.file) + try: + excel = Excels.read_opyxl(self.file) + except InvalidFileException: + raise ValueError( + self.py_name + "\n" + f"Cannot read the file '{self.file}'...\n" + f"It could happen that cell='{cellname}' was " + "read as a cell range name due to a wrong " + "definition of cell value" + ) + # Get global and local cellrange names global_cellranges = excel.defined_names local_cellranges = None # need to lower the sheetnames as Vensim has no case sensitivity for sheet in excel.sheetnames: - if sheet.lower() == self.sheet.lower(): + if sheet.lower() == self.tab.lower(): local_cellranges = excel[sheet].defined_names break @@ -179,8 +206,8 @@ def _get_data_from_file_opyxl(self, cellname): or global_cellranges.get(cellname) sheet, cells = next(cellrange.destinations) - assert sheet.lower() == self.sheet.lower() - self.sheet = sheet # case insensitivity in sheet name + assert sheet.lower() == self.tab.lower() + self.tab = sheet # case insensitivity in sheet name # Get the cells where the cellrange is defined cells = re.split(r":|\$", cells) @@ -573,7 +600,7 @@ def _file_sheet(self): Returns file and sheet name in a string """ return "\tFile name:\t'{}'\n".format(self.file)\ - + "\tSheet name:\t'{}'\n".format(self.sheet) + + "\tSheet name:\t'{}'\n".format(self.tab) @staticmethod def _col_to_num(col): @@ -704,11 +731,11 @@ class ExtData(External, Data): Class for Vensim GET XLS DATA/GET DIRECT DATA """ - def __init__(self, file_name, sheet, time_row_or_col, cell, + def __init__(self, file_name, tab, time_row_or_col, cell, interp, coords, root, final_coords, py_name): super().__init__(py_name) self.files = [file_name] - self.sheets = [sheet] + self.tabs = [tab] self.time_row_or_cols = [time_row_or_col] self.cells = [cell] self.coordss = [coords] @@ -725,13 +752,12 @@ def __init__(self, file_name, sheet, time_row_or_col, cell, + "'raw', 'interpolate', " + "'look_forward' or 'hold_backward'") - def add(self, file_name, sheet, time_row_or_col, cell, - interp, coords): + def add(self, file_name, tab, time_row_or_col, cell, interp, coords): """ Add information to retrieve new dimension in an already declared object """ self.files.append(file_name) - self.sheets.append(sheet) + self.tabs.append(tab) self.time_row_or_cols.append(time_row_or_col) self.cells.append(cell) self.coordss.append(coords) @@ -753,9 +779,9 @@ def initialize(self): """ if not self.coordss[0]: # Just load one value (no add) - for self.file, self.sheet, self.x_row_or_col, \ + for self.file, self.tab, self.x_row_or_col, \ self.cell, self.coords\ - in zip(self.files, self.sheets, self.time_row_or_cols, + in zip(self.files, self.tabs, self.time_row_or_cols, self.cells, self.coordss): self.data = self._initialize_data("data") else: @@ -763,9 +789,9 @@ def initialize(self): self.data = xr.DataArray( np.nan, self.final_coords, list(self.final_coords)) - for self.file, self.sheet, self.x_row_or_col, \ + for self.file, self.tab, self.x_row_or_col, \ self.cell, self.coords\ - in zip(self.files, self.sheets, self.time_row_or_cols, + in zip(self.files, self.tabs, self.time_row_or_cols, self.cells, self.coordss): values = self._initialize_data("data") @@ -789,11 +815,11 @@ class ExtLookup(External, Lookups): Class for Vensim GET XLS LOOKUPS/GET DIRECT LOOKUPS """ - def __init__(self, file_name, sheet, x_row_or_col, cell, coords, + def __init__(self, file_name, tab, x_row_or_col, cell, coords, root, final_coords, py_name): super().__init__(py_name) self.files = [file_name] - self.sheets = [sheet] + self.tabs = [tab] self.x_row_or_cols = [x_row_or_col] self.cells = [cell] self.coordss = [coords] @@ -802,12 +828,12 @@ def __init__(self, file_name, sheet, x_row_or_col, cell, coords, self.interp = "interpolate" self.is_float = not bool(coords) - def add(self, file_name, sheet, x_row_or_col, cell, coords): + def add(self, file_name, tab, x_row_or_col, cell, coords): """ Add information to retrieve new dimension in an already declared object """ self.files.append(file_name) - self.sheets.append(sheet) + self.tabs.append(tab) self.x_row_or_cols.append(x_row_or_col) self.cells.append(cell) self.coordss.append(coords) @@ -822,9 +848,9 @@ def initialize(self): """ if not self.coordss[0]: # Just loag one value (no add) - for self.file, self.sheet, self.x_row_or_col, \ + for self.file, self.tab, self.x_row_or_col, \ self.cell, self.coords\ - in zip(self.files, self.sheets, self.x_row_or_cols, + in zip(self.files, self.tabs, self.x_row_or_cols, self.cells, self.coordss): self.data = self._initialize_data("lookup") else: @@ -832,9 +858,9 @@ def initialize(self): self.data = xr.DataArray( np.nan, self.final_coords, list(self.final_coords)) - for self.file, self.sheet, self.x_row_or_col, \ + for self.file, self.tab, self.x_row_or_col, \ self.cell, self.coords\ - in zip(self.files, self.sheets, self.x_row_or_cols, + in zip(self.files, self.tabs, self.x_row_or_cols, self.cells, self.coordss): values = self._initialize_data("lookup") @@ -854,11 +880,11 @@ class ExtConstant(External): Class for Vensim GET XLS CONSTANTS/GET DIRECT CONSTANTS """ - def __init__(self, file_name, sheet, cell, coords, + def __init__(self, file_name, tab, cell, coords, root, final_coords, py_name): super().__init__(py_name) self.files = [file_name] - self.sheets = [sheet] + self.tabs = [tab] self.transposes = [ cell[-1] == '*' and np.prod(utils.compute_shape(coords)) > 1] self.cells = [cell.strip('*')] @@ -866,12 +892,12 @@ def __init__(self, file_name, sheet, cell, coords, self.root = root self.final_coords = final_coords - def add(self, file_name, sheet, cell, coords): + def add(self, file_name, tab, cell, coords): """ Add information to retrieve new dimension in an already declared object """ self.files.append(file_name) - self.sheets.append(sheet) + self.tabs.append(tab) self.transposes.append( cell[-1] == '*' and np.prod(utils.compute_shape(coords)) > 1) self.cells.append(cell.strip('*')) @@ -887,8 +913,8 @@ def initialize(self): """ if not self.coordss[0]: # Just loag one value (no add) - for self.file, self.sheet, self.transpose, self.cell, self.coords\ - in zip(self.files, self.sheets, self.transposes, + for self.file, self.tab, self.transpose, self.cell, self.coords\ + in zip(self.files, self.tabs, self.transposes, self.cells, self.coordss): self.data = self._initialize() else: @@ -897,8 +923,8 @@ def initialize(self): self.data = xr.DataArray( np.nan, self.final_coords, list(self.final_coords)) - for self.file, self.sheet, self.transpose, self.cell, self.coords\ - in zip(self.files, self.sheets, self.transposes, + for self.file, self.tab, self.transpose, self.cell, self.coords\ + in zip(self.files, self.tabs, self.transposes, self.cells, self.coordss): self.data.loc[self.coords] = self._initialize().values @@ -1012,10 +1038,10 @@ class ExtSubscript(External): Class for Vensim GET XLS SUBSCRIPT/GET DIRECT SUBSCRIPT """ - def __init__(self, file_name, sheet, firstcell, lastcell, prefix, root): + def __init__(self, file_name, tab, firstcell, lastcell, prefix, root): super().__init__("Hardcoded external subscript") self.file = file_name - self.sheet = sheet + self.tab = tab self.prefix = prefix self._resolve_file(root=root) split = self._split_excel_cell(firstcell) @@ -1054,10 +1080,26 @@ def get_subscripts_cell(self, row_first, col_first, lastcell): if col_last is not None: read_kwargs['usecols'] = np.arange(col_first, col_last+1) - data = pd.read_excel( - self.file, self.sheet, - skiprows=row_first-1, + # get the function to read the data based on its extension + ext = self.file.suffix.lower() + if ext in _SPREADSHEET_EXTS: + read_func = pd.read_excel + read_kwargs['sheet_name'] = self.tab + elif ext == '.csv': + read_func = pd.read_csv + if self.tab and not self.tab[0].isalnum(): + read_kwargs['sep'] = self.tab + else: + read_func = pd.read_table + if self.tab and not self.tab[0].isalnum(): + read_kwargs['sep'] = self.tab + + # read the data + data = read_func( + self.file, + skiprows=row_first, dtype=object, + header=None, **read_kwargs ).values @@ -1069,12 +1111,21 @@ def get_subscripts_cell(self, row_first, col_first, lastcell): def get_subscripts_name(self, cellname): """Get subscripts from cell range name definition""" - excel = load_workbook(self.file, read_only=True, data_only=True) + try: + excel = load_workbook(self.file, read_only=True, data_only=True) + except InvalidFileException: + raise ValueError( + self.py_name + "\n" + f"Cannot read the file '{self.file}'...\n" + f"It could happen that firstcell='{cellname}' was " + "read as a cell range name due to a wrong definition " + "of cell value" + ) global_cellranges = excel.defined_names local_cellranges = None # need to lower the sheetnames as Vensim has no case sensitivity for sheet in excel.sheetnames: - if sheet.lower() == self.sheet.lower(): + if sheet.lower() == self.tab.lower(): local_cellranges = excel[sheet].defined_names break @@ -1091,8 +1142,8 @@ def get_subscripts_name(self, cellname): or global_cellranges.get(cellname) sheet, cells = next(cellrange.destinations) - assert sheet.lower() == self.sheet.lower() - self.sheet = sheet # case insensitivity in sheet name + assert sheet.lower() == self.tab.lower() + self.tab = sheet # case insensitivity in sheet name # Get the cells where the cellrange is defined first_cell, last_cell = cells.replace("$", '').split(":") diff --git a/pysd/py_backend/model.py b/pysd/py_backend/model.py index 2db13ad7..dcce0090 100644 --- a/pysd/py_backend/model.py +++ b/pysd/py_backend/model.py @@ -544,7 +544,6 @@ def initialize_external_data(self, externals=None): except ValueError: # pragma: no cover raise ModuleNotFoundError("No module named 'netCDF4'") - for ext in self._external_elements: if ext.py_name in ds.data_vars.keys(): # Initialize external from nc file @@ -753,7 +752,7 @@ def __include_for_serialization(self, ext, py_name_clean, data, metadata, for col in self._doc.columns } var_meta["files"] = ";".join(ext.files) - var_meta["sheets"] = ";".join(ext.sheets) + var_meta["tabs"] = ";".join(ext.tabs) var_meta["cells"] = ";".join(ext.cells) # TODO: add also time_row_or_cols diff --git a/pysd/translators/structures/abstract_expressions.py b/pysd/translators/structures/abstract_expressions.py index 07e02dec..5af36388 100644 --- a/pysd/translators/structures/abstract_expressions.py +++ b/pysd/translators/structures/abstract_expressions.py @@ -558,7 +558,8 @@ class GetLookupsStructure(AbstractSyntax): file: str The file path where the data is. tab: str - The sheetname where the data is. + Tab name from which the data is read. If file type is not a + spreadsheet this will be used as a separator. x_row_or_col: str The pointer to the cell or cellrange name that defines the interpolation series data. @@ -587,7 +588,8 @@ class GetDataStructure(AbstractSyntax): file: str The file path where the data is. tab: str - The sheetname where the data is. + Tab name from which the data is read. If file type is not a + spreadsheet this will be used as a separator. time_row_or_col: str The pointer to the cell or cellrange name that defines the interpolation time series data. @@ -616,7 +618,8 @@ class GetConstantsStructure(AbstractSyntax): file: str The file path where the data is. tab: str - The sheetname where the data is. + Tab name from which the data is read. If file type is not a + spreadsheet this will be used as a separator. cell: str The pointer to the cell or the cellrange name that defines the data. diff --git a/pysd/translators/vensim/parsing_grammars/lookups.peg b/pysd/translators/vensim/parsing_grammars/lookups.peg index c4a731b8..1088337f 100644 --- a/pysd/translators/vensim/parsing_grammars/lookups.peg +++ b/pysd/translators/vensim/parsing_grammars/lookups.peg @@ -2,6 +2,4 @@ lookup = _ "(" _ (regularLookup / excelLookup) _ ")" regularLookup = limits? _ ( "(" _ number _ "," _ number _ ")" _ ","? _ )+ -excelLookup = ~"GET( |_)(XLS|DIRECT)( |_)LOOKUPS"I _ "(" (args _ ","? _)+ ")" - -args = ~r"[^,()]*" +excelLookup = ~"GET( |_)(XLS|DIRECT)( |_)LOOKUPS"I _ "(" _ (string _ ","? _)+ ")" diff --git a/pysd/translators/vensim/vensim_element.py b/pysd/translators/vensim/vensim_element.py index a67a7e7d..e135328f 100644 --- a/pysd/translators/vensim/vensim_element.py +++ b/pysd/translators/vensim/vensim_element.py @@ -124,6 +124,7 @@ def __init__(self, ast): self.subscripts = [] self.subscripts_except = [] self.subscripts_except_groups = [] + self.qargs = [] self.name = None self.expression = None self.keyword = None @@ -166,14 +167,17 @@ def visit_keyword(self, n, vc): self.keyword = n.text.strip()[1:-1].lower().replace(" ", "_") def visit_imported_subscript(self, n, vc): - self.subscripts = { - arg_name: argument.strip().strip("'") - for arg_name, argument - in zip( - ("file", "tab", "firstcell", "lastcell", "prefix"), - vc[4].split(",") - ) - } + self.subscripts = dict( + file=self.qargs[0], + tab=self.qargs[1], + firstcell=self.qargs[2], + lastcell=self.qargs[3], + prefix=self.qargs[4] + ) + + def visit_string(self, n, vc): + self.qargs.append(vc[1]) + return vc[1] def visit_subscript_copy(self, n, vc): self.component = SubscriptRange(self.name, vc[4].strip()) @@ -635,6 +639,7 @@ class LookupsVisitor(parsimonious.NodeVisitor): """Visit the elements of a lookups to get the AST""" def __init__(self, ast): self.translation = None + self.qargs = [] self.visit(ast) def visit_limits(self, n, vc): @@ -658,15 +663,17 @@ def visit_regularLookup(self, n, vc): ) def visit_excelLookup(self, n, vc): - arglist = vc[3].split(",") - self.translation = structures["get_xls_lookups"]( - file=eval(arglist[0]), - tab=eval(arglist[1]), - x_row_or_col=eval(arglist[2]), - cell=eval(arglist[3]) + file=self.qargs[0], + tab=self.qargs[1], + x_row_or_col=self.qargs[2], + cell=self.qargs[3] ) + def visit_string(self, n, vc): + self.qargs.append(vc[1]) + return vc[1] + def generic_visit(self, n, vc): return "".join(filter(None, vc)) or n.text diff --git a/tests/data/input.csv b/tests/data/input.csv new file mode 100644 index 00000000..878f2727 --- /dev/null +++ b/tests/data/input.csv @@ -0,0 +1,5 @@ +,1,2,3,4,5,6,7,8,9,10,, +A,0,0,1,1,-1,-1,0,0,,, +B,0,1,1,-1,-1,0,0,0,,, +C,1,1,-1,-1,0,0,0,0,,, +,,,,,,,,,,,, diff --git a/tests/data/input.tab b/tests/data/input.tab new file mode 100644 index 00000000..4b0e48c8 --- /dev/null +++ b/tests/data/input.tab @@ -0,0 +1,5 @@ + 1 2 3 4 5 6 7 8 9 10 +A 0 0 1 1 -1 -1 0 0 +B 0 1 1 -1 -1 0 0 0 +C 1 1 -1 -1 0 0 0 0 + diff --git a/tests/data/input.txt b/tests/data/input.txt new file mode 100644 index 00000000..317d2cc7 --- /dev/null +++ b/tests/data/input.txt @@ -0,0 +1,5 @@ +=1=2=3=4=5=6=7=8=9=10== +A=0=0=1=1=-1=-1=0=0=== +B=0=1=1=-1=-1=0=0=0=== +C=1=1=-1=-1=0=0=0=0=== +============ diff --git a/tests/data/input2.csv b/tests/data/input2.csv new file mode 100644 index 00000000..43448bec --- /dev/null +++ b/tests/data/input2.csv @@ -0,0 +1,5 @@ +;1;2;3;4;5;6;7;8;9;10;; +A;0;0;1;1;-1;-1;0;0;;; +B;0;1;1;-1;-1;0;0;0;;; +C;1;1;-1;-1;0;0;0;0;;; +;;;;;;;;;;;; diff --git a/tests/data/not_implemented_file.ods b/tests/data/not_implemented_file.ods deleted file mode 100644 index a56eb466..00000000 Binary files a/tests/data/not_implemented_file.ods and /dev/null differ diff --git a/tests/pytest_builders/pytest_python.py b/tests/pytest_builders/pytest_python.py index 67890d5a..f23cb86e 100644 --- a/tests/pytest_builders/pytest_python.py +++ b/tests/pytest_builders/pytest_python.py @@ -190,19 +190,32 @@ def test_referencebuilder_subscripts_nowarning(self, component, class TestSubscriptManager: @pytest.mark.parametrize( - "arguments,raise_type,error_message", + "asrs,raise_type,error_message", [ ( # invalid definition - [[AbstractSubscriptRange("my subs", 5, [])], Path("here")], + [AbstractSubscriptRange("my subs", 5, [])], ValueError, "Invalid definition of subscript 'my subs':\n\t5" ), + ( # empty range exts + [AbstractSubscriptRange("my subs", dict( + file="data/input.csv", + tab="", + firstcell="A5", + lastcell="5", + prefix="sr" + ), [])], + ValueError, + "Subscript range 'my subs' empty:\n\t" + "{'file': 'data/input.csv', 'tab': '', " + "'firstcell': 'A5', 'lastcell': '5', 'prefix': 'sr'}" + ), ], - ids=["invalid definition"] + ids=["invalid definition", "empty range exts"] ) - def test_invalid_subscripts(self, arguments, raise_type, error_message): + def test_invalid_subscripts(self, asrs, raise_type, error_message, _root): with pytest.raises(raise_type, match=error_message): - SubscriptManager(*arguments) + SubscriptManager(asrs, _root) class TestNamespaceManager: diff --git a/tests/pytest_pysd/pytest_serialize_externals.py b/tests/pytest_pysd/pytest_serialize_externals.py index 33f45d77..639ae6aa 100644 --- a/tests/pytest_pysd/pytest_serialize_externals.py +++ b/tests/pytest_pysd/pytest_serialize_externals.py @@ -50,7 +50,7 @@ def test_serialize_externals_file_content(self, tmp_path, model): assert "description" in ds.attrs.keys() assert all(map( lambda x: x in ds.data_vars["_ext_data_data_forward"].attrs.keys(), - ["Py Name", "sheets", "files"])) + ["Py Name", "tabs", "files"])) @pytest.mark.parametrize( "model_path,include,exclude", diff --git a/tests/pytest_types/external/pytest_external.py b/tests/pytest_types/external/pytest_external.py index e5296531..1f699e7b 100644 --- a/tests/pytest_types/external/pytest_external.py +++ b/tests/pytest_types/external/pytest_external.py @@ -275,7 +275,7 @@ def test_read_empty_cells_openpyxl(self, _root): ext = External("external") ext.file = "data/input.xlsx" - ext.sheet = "Horizontal missing" + ext.tab = "Horizontal missing" ext._resolve_file(root=_root) error_message = r"external\nThe cells are empty\.\n"\ @@ -294,7 +294,7 @@ def test_read_empty_cells_pandas(self, _root): ext = External("external") ext.file = "data/input.xlsx" - ext.sheet = "Horizontal missing" + ext.tab = "Horizontal missing" ext._resolve_file(root=_root) error_message = r"external\nThe cells are empty\.\n" @@ -339,7 +339,7 @@ def test_data_interp_h1d_1(self, _root): py_name = "test_data_interp_h1d_1" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -372,7 +372,7 @@ def test_data_interp_hn1d_1(self, _root): py_name = "test_data_interp_h1d_1" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -402,7 +402,7 @@ def test_data_interp_h1d(self, _root, _exp): py_name = "test_data_interp_h1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -432,7 +432,7 @@ def test_data_interp_v1d(self, _root, _exp): py_name = "test_data_interp_v1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -462,7 +462,7 @@ def test_data_interp_hn1d(self, _root, _exp): py_name = "test_data_interp_h1nd" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -492,7 +492,7 @@ def test_data_interp_vn1d(self, _root, _exp): py_name = "test_data_interp_vn1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -522,7 +522,7 @@ def test_data_forward_h1d(self, _root, _exp): py_name = "test_data_forward_h1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -552,7 +552,7 @@ def test_data_forward_v1d(self, _root, _exp): py_name = "test_data_forward_v1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -582,7 +582,7 @@ def test_data_forward_hn1d(self, _root, _exp): py_name = "test_data_forward_hn1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -612,7 +612,7 @@ def test_data_forward_vn1d(self, _root, _exp): py_name = "test_data_forward_vn1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -642,7 +642,7 @@ def test_data_backward_h1d(self, _root, _exp): py_name = "test_data_backward_h1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -672,7 +672,7 @@ def test_data_backward_v1d(self, _root, _exp): py_name = "test_data_backward_v1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -702,7 +702,7 @@ def test_data_backward_hn1d(self, _root, _exp): py_name = "test_data_backward_hn1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -732,7 +732,7 @@ def test_data_backward_vn1d(self, _root, _exp): py_name = "test_data_backward_vn1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -762,7 +762,7 @@ def test_data_interp_vn2d(self, _root, _exp): py_name = "test_data_interp_vn2d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -791,7 +791,7 @@ def test_data_forward_hn2d(self, _root, _exp): py_name = "test_data_forward_hn2d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -820,7 +820,7 @@ def test_data_backward_v2d(self, _root, _exp): py_name = "test_data_backward_v2d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -853,7 +853,7 @@ def test_data_interp_h3d(self, _root, _exp): py_name = "test_data_interp_h3d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -863,7 +863,7 @@ def test_data_interp_h3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, coords=coords_2, @@ -893,7 +893,7 @@ def test_data_forward_v3d(self, _root, _exp): py_name = "test_data_forward_v3d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -903,7 +903,7 @@ def test_data_forward_v3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, coords=coords_2, @@ -933,7 +933,7 @@ def test_data_backward_hn3d(self, _root, _exp): py_name = "test_data_backward_hn3d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -943,7 +943,7 @@ def test_data_backward_hn3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, coords=coords_2, @@ -970,7 +970,7 @@ def test_data_raw_h1d(self, _root, _exp): py_name = "test_data_forward_h1d" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -1013,7 +1013,7 @@ def test_lookup_h1d(self, _root, _exp): py_name = "test_lookup_h1d" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -1041,7 +1041,7 @@ def test_lookup_v1d(self, _root, _exp): py_name = "test_lookup_v1d" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -1069,7 +1069,7 @@ def test_lookup_hn1d(self, _root, _exp): py_name = "test_lookup_h1nd" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -1097,7 +1097,7 @@ def test_lookup_vn1d(self, _root, _exp): py_name = "test_lookup_vn1d" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -1125,7 +1125,7 @@ def test_lookup_h2d(self, _root, _exp): py_name = "test_lookup_h2d" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -1156,7 +1156,7 @@ def test_lookup_vn3d(self, _root, _exp): py_name = "test_lookup_vn3d" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -1165,7 +1165,7 @@ def test_lookup_vn3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -1194,7 +1194,7 @@ def test_lookup_vn3d_shape0(self, _root, _exp): py_name = "test_lookup_vn3d_shape0" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -1203,7 +1203,7 @@ def test_lookup_vn3d_shape0(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -1230,7 +1230,7 @@ def test_lookup_vn2d_xarray(self, _root): py_name = "test_lookup_vn2d_xarray" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -1293,7 +1293,7 @@ def test_lookup_vn3d_xarray(self, _root): py_name = "test_lookup_vn3d_xarray" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -1302,7 +1302,7 @@ def test_lookup_vn3d_xarray(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -1364,7 +1364,7 @@ def test_constant_0d(self, _root): py_name = "test_constant_0d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1372,7 +1372,7 @@ def test_constant_0d(self, _root): py_name=py_name) data2 = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell2, coords=coords, @@ -1398,7 +1398,7 @@ def test_constant_n0d(self, _root): py_name = "test_constant_0d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1406,7 +1406,7 @@ def test_constant_n0d(self, _root): py_name=py_name) data2 = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell2, coords=coords, @@ -1431,7 +1431,7 @@ def test_constant_h1d(self, _root, _exp): py_name = "test_constant_h1d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1454,7 +1454,7 @@ def test_constant_v1d(self, _root, _exp): py_name = "test_constant_v1d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1477,7 +1477,7 @@ def test_constant_hn1d(self, _root, _exp): py_name = "test_constant_hn1d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1500,7 +1500,7 @@ def test_constant_vn1d(self, _root, _exp): py_name = "test_constant_vn1d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1523,7 +1523,7 @@ def test_constant_h2d(self, _root, _exp): py_name = "test_constant_h2d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1546,7 +1546,7 @@ def test_constant_v2d(self, _root, _exp): py_name = "test_constant_v2d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1569,7 +1569,7 @@ def test_constant_hn2d(self, _root, _exp): py_name = "test_constant_hn2d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1592,7 +1592,7 @@ def test_constant_vn2d(self, _root, _exp): py_name = "test_constant_vn2d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1624,7 +1624,7 @@ def test_constant_h3d(self, _root, _exp): py_name = "test_constant_h3d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1632,7 +1632,7 @@ def test_constant_h3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell2, coords=coords2) @@ -1662,7 +1662,7 @@ def test_constant_v3d(self, _root, _exp): py_name = "test_constant_v3d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1670,7 +1670,7 @@ def test_constant_v3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell2, coords=coords2) @@ -1700,7 +1700,7 @@ def test_constant_hn3d(self, _root, _exp): py_name = "test_constant_hn3d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1708,7 +1708,7 @@ def test_constant_hn3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell2, coords=coords2) @@ -1738,7 +1738,7 @@ def test_constant_vn3d(self, _root, _exp): py_name = "test_constant_vn2d" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -1746,7 +1746,7 @@ def test_constant_vn3d(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell2, coords=coords2) @@ -1754,6 +1754,189 @@ def test_constant_vn3d(self, _root, _exp): assert data().equals(_exp.constant_3d) + def test_constant_h1d_csv(self, _root, _exp): + """ + ExtConstant test for horizontal 1d data + """ + import pysd + + file_name = "data/input.csv" + sheet = "" + cell = "B2" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8]} + py_name = "test_constant_h1d_csv" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_1d) + + def test_constant_h2d_csv(self, _root, _exp): + """ + ExtConstant test for horizontal 2d data + """ + import pysd + + file_name = "data/input.csv" + sheet = "," + cell = "B2" + coords = {'ABC': ['A', 'B', 'C'], 'val': [0, 1, 2, 3, 5, 6, 7, 8]} + py_name = "test_constant_h2d_csv" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d) + + def test_constant_v2d_csv(self, _root, _exp): + """ + ExtConstant test for vertical 2d data + """ + import pysd + + file_name = "data/input.csv" + sheet = "vertical" + cell = "B2*" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8], 'ABC': ['A', 'B', 'C']} + py_name = "test_constant_v2d_csv" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d.transpose()) + + def test_constant_v2d_csv2(self, _root, _exp): + """ + ExtConstant test for vertical 2d data + """ + import pysd + + file_name = "data/input2.csv" + sheet = ";" + cell = "B2*" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8], 'ABC': ['A', 'B', 'C']} + py_name = "test_constant_v2d_csv2" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d.transpose()) + + def test_constant_h1d_tab(self, _root, _exp): + """ + ExtConstant test for horizontal 1d data + """ + import pysd + + file_name = "data/input.tab" + sheet = "" + cell = "B2" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8]} + py_name = "test_constant_h1d_tab" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_1d) + + def test_constant_h2d_tab(self, _root, _exp): + """ + ExtConstant test for horizontal 2d data + """ + import pysd + + file_name = "data/input.tab" + sheet = "\t" + cell = "B2" + coords = {'ABC': ['A', 'B', 'C'], 'val': [0, 1, 2, 3, 5, 6, 7, 8]} + py_name = "test_constant_h2d_tab" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d) + + def test_constant_v2d_tab(self, _root, _exp): + """ + ExtConstant test for vertical 2d data + """ + import pysd + + file_name = "data/input.tab" + sheet = "vertical" + cell = "B2*" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8], 'ABC': ['A', 'B', 'C']} + py_name = "test_constant_v2d_tab" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d.transpose()) + + def test_constant_v2d_txt(self, _root, _exp): + """ + ExtConstant test for vertical 2d data + """ + import pysd + + file_name = "data/input.txt" + sheet = "=" + cell = "B2*" + coords = {'val': [0, 1, 2, 3, 5, 6, 7, 8], 'ABC': ['A', 'B', 'C']} + py_name = "test_constant_v2d_txt" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + data.initialize() + + assert data().equals(_exp.constant_2d.transpose()) class TestSubscript(): """ @@ -1776,7 +1959,7 @@ def test_subscript_h(self, _root): 'val5', 'val6', 'val7', 'val8'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1799,7 +1982,76 @@ def test_subscript_h2(self, _root): 'v5', 'v6', 'v7', 'v8'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_h_csv(self, _root): + """ + ExtSubscript test for horizontal subscripts + """ + import pysd + + file_name = "data/input.csv" + sheet = "" + firstcell = "A1" + lastcell = "1" + prefix = 'h' + expected = ['h1', 'h2', 'h3', 'h4', 'h5', + 'h6', 'h7', 'h8', 'h9', 'h10'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_h_tab(self, _root): + """ + ExtSubscript test for horizontal subscripts + """ + import pysd + + file_name = "data/input.tab" + sheet = "" + firstcell = "B1" + lastcell = "1" + prefix = 'h' + expected = ['h1', 'h2', 'h3', 'h4', 'h5', + 'h6', 'h7', 'h8', 'h9', 'h10'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_h_txt(self, _root): + """ + ExtSubscript test for horizontal subscripts + """ + import pysd + + file_name = "data/input.txt" + sheet = "=" + firstcell = "B1" + lastcell = "1" + prefix = 'h' + expected = ['h1', 'h2', 'h3', 'h4', 'h5', + 'h6', 'h7', 'h8', 'h9', 'h10'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1821,7 +2073,7 @@ def test_subscript_v(self, _root): expected = ['A', 'B', 'C'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1843,7 +2095,73 @@ def test_subscript_v2(self, _root): expected = ['A', 'B', 'C', '4', '5'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_v_csv(self, _root): + """ + ExtSubscript test for vertical subscripts + """ + import pysd + + file_name = "data/input.csv" + sheet = "," + firstcell = "A2" + lastcell = "A" + prefix = 'v' + expected = ['vA', 'vB', 'vC'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_v_tab(self, _root): + """ + ExtSubscript test for vertical subscripts + """ + import pysd + + file_name = "data/input.tab" + sheet = "\t" + firstcell = "A1" + lastcell = "A" + prefix = 'v' + expected = ['vA', 'vB', 'vC'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_v_ncsv(self, _root): + """ + ExtSubscript test for vertical subscripts + """ + import pysd + + file_name = "data/input2.csv" + sheet = ";" + firstcell = "A1" + lastcell = "A" + prefix = 'v' + expected = ['vA', 'vB', 'vC'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1865,7 +2183,7 @@ def test_subscript_d(self, _root): expected = ['X', 'A', 'B', 'C', 'Y', 'A', 'B', 'C'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1887,7 +2205,51 @@ def test_subscript_d2(self, _root): expected = ['j3', 'j2', 'j1', 'j6', 'j4', 'j8', 'j-1', 'j3', 'j2'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_d_csv(self, _root): + """ + ExtSubscript test for diagonal subscripts + """ + import pysd + + file_name = "data/input.csv" + sheet = "123 name" + firstcell = "B1" + lastcell = "C2" + prefix = 'd' + expected = ['d1', 'd2', 'd0', 'd0'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_d_tab(self, _root): + """ + ExtSubscript test for diagonal subscripts + """ + import pysd + + file_name = "data/input.tab" + sheet = "sheet name!" + firstcell = "B1" + lastcell = "C2" + prefix = 'd' + expected = ['d1', 'd2', 'd0', 'd0'] + + data = pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1910,7 +2272,7 @@ def test_subscript_name_h(self, _root): 'l5', 'l6', 'l7', 'l8'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1932,7 +2294,7 @@ def test_subscript_name_v(self, _root): expected = ['pA', 'pB', 'pC'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1954,7 +2316,7 @@ def test_subscript_name_d(self, _root): expected = ['X', 'A', '0', 'B', '0', 'C', '1'] data = pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -1968,34 +2330,6 @@ class TestWarningsErrors(): Test for the warnings and errors of External and its subclasses """ - def test_not_implemented_file(self, _root): - """ - Test for not implemented file - """ - import pysd - - file_name = "data/not_implemented_file.ods" - sheet = "Horizontal" - time_row_or_col = "4" - cell = "C5" - coords = {} - interp = None - py_name = "test_not_implemented_file" - - data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, - time_row_or_col=time_row_or_col, - root=_root, - cell=cell, - coords=coords, - interp=interp, - final_coords=coords, - py_name=py_name) - - error_message = r"The files with extension .ods are not implemented" - with pytest.raises(NotImplementedError, match=error_message): - data.initialize() - def test_non_existent_file(self, _root): """ Test for non-existent file @@ -2011,7 +2345,7 @@ def test_non_existent_file(self, _root): py_name = "test_non_existent_file" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2038,7 +2372,7 @@ def test_non_existent_sheet_pyxl(self, _root): py_name = "test_non_existent_sheet_pyxl" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2066,7 +2400,7 @@ def test_non_existent_cellrange_name_pyxl(self, _root): py_name = "test_non_existent_cellrange_name_pyxl" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2092,7 +2426,7 @@ def test_non_existent_cellrange_name_in_sheet_pyxl(self, _root): py_name = "est_non_existent_cellrange_name_in_sheet_pyxl" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -2123,7 +2457,7 @@ def test_data_interp_h1dm_row(self, _root): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2161,7 +2495,7 @@ def test_data_interp_h1dm_row2(self, _root): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2201,7 +2535,7 @@ def test_data_interp_h1dm(self, _root, _exp): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2237,7 +2571,7 @@ def test_data_interp_h1dm_ignore(self, _root, _exp): pysd.external.External.missing = "ignore" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2272,7 +2606,7 @@ def test_data_interp_h1dm_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2303,7 +2637,7 @@ def test_data_interp_v1dm(self, _root, _exp): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2339,7 +2673,7 @@ def test_data_interp_v1dm_ignore(self, _root, _exp): pysd.external.External.missing = "ignore" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2374,7 +2708,7 @@ def test_data_interp_v1dm_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2405,7 +2739,7 @@ def test_data_interp_hn1dm(self, _root, _exp): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2441,7 +2775,7 @@ def test_data_interp_hn1dm_ignore(self, _root, _exp): pysd.external.External.missing = "ignore" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2476,7 +2810,7 @@ def test_data_interp_hn1dm_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2510,7 +2844,7 @@ def test_data_interp_hn3dmd(self, _root, _exp): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -2520,7 +2854,7 @@ def test_data_interp_hn3dmd(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, interp=interp, @@ -2556,7 +2890,7 @@ def test_data_interp_hn3dmd_raw(self, _root): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -2566,7 +2900,7 @@ def test_data_interp_hn3dmd_raw(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, interp=interp, @@ -2594,7 +2928,7 @@ def test_lookup_hn3dmd_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -2603,7 +2937,7 @@ def test_lookup_hn3dmd_raise(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -2631,7 +2965,7 @@ def test_lookup_hn3dmd_ignore(self, _root, _exp): pysd.external.External.missing = "ignore" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -2640,7 +2974,7 @@ def test_lookup_hn3dmd_ignore(self, _root, _exp): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -2674,7 +3008,7 @@ def test_constant_h3dm(self, _root): pysd.external.External.missing = "warning" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell_1, coords=coords_1, @@ -2682,7 +3016,7 @@ def test_constant_h3dm(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell_2, coords=coords_2) @@ -2710,7 +3044,7 @@ def test_constant_h3dm_ignore(self, _root): pysd.external.External.missing = "ignore" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell_1, coords=coords_1, @@ -2718,7 +3052,7 @@ def test_constant_h3dm_ignore(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell_2, coords=coords_2) @@ -2744,7 +3078,7 @@ def test_constant_h3dm_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell_1, coords=coords_1, @@ -2752,7 +3086,7 @@ def test_constant_h3dm_raise(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell_2, coords=coords_2) @@ -2781,7 +3115,7 @@ def test_constant_hn3dm_raise(self, _root): pysd.external.External.missing = "raise" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell_1, coords=coords_1, @@ -2789,7 +3123,7 @@ def test_constant_hn3dm_raise(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell_2, coords=coords_2) @@ -2812,7 +3146,7 @@ def test_data_interp_h1d0(self, _root): py_name = "test_data_interp_h1d0" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2840,7 +3174,7 @@ def test_data_interp_v1d0(self, _root): py_name = "test_data_interp_v1d0" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2870,7 +3204,7 @@ def test_data_interp_hn1d0(self, _root): pysd.external.External.missing = "warning" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2899,7 +3233,7 @@ def test_data_interp_hn1dt(self, _root): py_name = "test_data_interp_h1dt" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2928,7 +3262,7 @@ def test_data_interp_hns(self, _root): py_name = "test_data_interp_hns" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2957,7 +3291,7 @@ def test_data_interp_vnss(self, _root): py_name = "test_data_interp_vnss" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -2987,7 +3321,7 @@ def test_data_interp_hnnwd(self, _root): py_name = "test_data_interp_hnnwd" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3014,7 +3348,7 @@ def test_data_raw_hnnm(self, _root): py_name = "test_data_interp_hnnm" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3037,7 +3371,7 @@ def test_data_raw_hnnm(self, _root): py_name = "test_data_interp_hnnnm2" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3074,7 +3408,7 @@ def test_data_h3d_interpnv(self, _root): r"'raw', 'interpolate', 'look_forward' or 'hold_backward'" with pytest.raises(ValueError, match=error_message): pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3102,7 +3436,7 @@ def test_data_h3d_interp(self, _root): py_name = "test_data_h3d_interp" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -3115,7 +3449,7 @@ def test_data_h3d_interp(self, _root): "previously defined one" with pytest.raises(ValueError, match=error_message): data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, coords=coords_2, @@ -3139,7 +3473,7 @@ def test_data_h3d_add(self, _root): py_name = "test_data_h3d_add" data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell_1, @@ -3151,7 +3485,7 @@ def test_data_h3d_add(self, _root): error_message = "Error matching dimensions with previous data" with pytest.raises(ValueError, match=error_message): data.add(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, cell=cell_2, coords=coords_2, @@ -3174,7 +3508,7 @@ def test_lookup_h3d_add(self, _root): py_name = "test_lookup_h3d_add" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -3185,7 +3519,7 @@ def test_lookup_h3d_add(self, _root): error_message = "Error matching dimensions with previous data" with pytest.raises(ValueError, match=error_message): data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -3211,7 +3545,7 @@ def test_constant_h3d_add(self, _root): py_name = "test_constant_h3d_add" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -3221,7 +3555,7 @@ def test_constant_h3d_add(self, _root): error_message = "Error matching dimensions with previous data" with pytest.raises(ValueError, match=error_message): data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell2, coords=coords2) @@ -3239,7 +3573,7 @@ def test_constant_hns(self, _root): py_name = "test_constant_hns" data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -3266,7 +3600,7 @@ def text_openpyxl_str(self, _root): py_name = "test_openpyxl_str" data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell, @@ -3287,7 +3621,7 @@ def text_openpyxl_str(self, _root): sheet = "caSE anD NON V" # test case insensitivity data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell, coords=coords, @@ -3313,7 +3647,7 @@ def test_subscript_name_non_existent_sheet(self, _root): error_message = r"The sheet doesn't exist\.\.\." with pytest.raises(ValueError, match=error_message): pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -3334,7 +3668,56 @@ def test_subscript_name_non_existent_cellrange_name(self, _root): error_message = "The cellrange name 'fake-cell'\nDoesn't exist in" with pytest.raises(AttributeError, match=error_message): pysd.external.ExtSubscript(file_name=file_name, - sheet=sheet, + tab=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + def test_name_in_tab(self, _root): + """ + Test for cellrange input in cell for non spreadsheet file + """ + import pysd + + file_name = "data/input.csv" + sheet = "" + cell = "data" + coords = {} + py_name = "test_name_in_tab" + + data = pysd.external.ExtConstant(file_name=file_name, + tab=sheet, + root=_root, + cell=cell, + coords=coords, + final_coords=coords, + py_name=py_name) + + error_message = r"Cannot read the file '.*'...\n"\ + "It could happen that cell='data' was read as a "\ + "cell range name due to a wrong definition of cell value" + with pytest.raises(ValueError, match=error_message): + data.initialize() + + def test_subscript_name_in_csv(self, _root): + """ + Test for cellrange input in cell for non spreadsheet file + """ + import pysd + + file_name = "data/input.csv" + sheet = "" + firstcell = "fake-cell" + lastcell = "" + prefix = "" + + error_message = r"Cannot read the file '.*'...\n"\ + "It could happen that firstcell='fake-cell' was read as a "\ + "cell range name due to a wrong definition of cell value" + with pytest.raises(ValueError, match=error_message): + pysd.external.ExtSubscript(file_name=file_name, + tab=sheet, root=_root, firstcell=firstcell, lastcell=lastcell, @@ -3379,7 +3762,7 @@ def test_constant_hn3dm_keep(self, _root): ['XY', 'ABC', 'val']) data = pysd.external.ExtConstant(file_name=file_name, - sheet=sheet, + tab=sheet, root=_root, cell=cell_1, coords=coords_1, @@ -3387,7 +3770,7 @@ def test_constant_hn3dm_keep(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, cell=cell_2, coords=coords_2) @@ -3435,7 +3818,7 @@ def test_lookup_hn3dmd_keep(self, _root): ['lookup_dim', 'XY', 'ABC']) data = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, root=_root, cell=cell_1, @@ -3444,7 +3827,7 @@ def test_lookup_hn3dmd_keep(self, _root): py_name=py_name) data.add(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=x_row_or_col, cell=cell_2, coords=coords_2) @@ -3476,7 +3859,7 @@ def test_data_interp_v1dm_keep(self, _root): ['time']) data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3512,7 +3895,7 @@ def test_data_interp_hnnm_keep(self, _root): ['time']) data = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3541,7 +3924,7 @@ def test_lookup_data_attr(self, _root): py_name = "test_data_interp_hnnm" datD = pysd.external.ExtData(file_name=file_name, - sheet=sheet, + tab=sheet, time_row_or_col=time_row_or_col, root=_root, cell=cell, @@ -3551,7 +3934,7 @@ def test_lookup_data_attr(self, _root): py_name=py_name) datL = pysd.external.ExtLookup(file_name=file_name, - sheet=sheet, + tab=sheet, x_row_or_col=time_row_or_col, root=_root, cell=cell,