Skip to content

Commit

Permalink
Merge pull request #34 from david-salac/feature/nd-exports
Browse files Browse the repository at this point in the history
Fixed computational variables
  • Loading branch information
david-salac authored Jan 19, 2021
2 parents 0961e67 + a361f15 commit 661c345
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 17 deletions.
2 changes: 1 addition & 1 deletion portable_spreadsheet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
from .grammar_utils import GrammarUtils # noqa
from .skipped_label import SkippedLabel # noqa

__version__ = "2.1.1"
__version__ = "2.1.2"
__status__ = "Production"
26 changes: 20 additions & 6 deletions portable_spreadsheet/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ class Cell(object):
_description (Optional[str]): Optional description of the cell.
_excel_row_position (Optional[int]): Position of the variable in
variable sheet in Excel.
_is_computational_variable (bool): If True, variable is computational.
_variable_words (WordConstructor): The word defining computational
operations of (computational) variable. Computational variable is
variable defined by formulas.
"""
def __init__(self,
row: Optional[int] = None,
Expand Down Expand Up @@ -80,14 +82,15 @@ def __init__(self,
self._excel_format: dict = {}
self._description: Optional[str] = None
self._excel_row_position: Optional[int] = None
self._is_computational_variable: bool = False

if words is not None:
self._constructing_words: WordConstructor = words
else:
self._constructing_words: WordConstructor = \
WordConstructor.init_from_new_cell(self)

self._variable_words: WordConstructor = None

# === CLASS METHODS and PROPERTIES: ===
@property
def word(self) -> WordConstructor:
Expand Down Expand Up @@ -173,6 +176,18 @@ def parse(self) -> Dict[str, str]:
"""
return self._constructing_words.parse(self)

@property
def parse_variable(self) -> Dict[str, str]:
"""Return the dictionary with keys: language, values: constructing
word. This function is called when the cell should be inserted to
a variable spreadsheet. This differs from 'parse' as variables
might be computational.
Returns:
Dict[str, str]: Words for each language
"""
return self._constructing_words.parse(self, True)

@property
def excel_format(self) -> dict:
"""Return style/format of the cell for Excel.
Expand Down Expand Up @@ -224,14 +239,13 @@ def excel_row_position(self, value: Optional[int]):
@property
def computational_variable(self):
"""Return True, if the variable is computational (contains some
formulas). False, if it is only value.
formulas). False, if it is only a value.
Returns:
bool: True, if the variable is computational (contains some
formulas). False, if it is only value.
"""
if self.is_variable:
return self._is_computational_variable
return False
return self._variable_words is not None

@property
def description(self) -> Optional[str]:
Expand Down
6 changes: 3 additions & 3 deletions portable_spreadsheet/grammars.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
"separator": "",
"row_first": False
},
# Like $'Sheet 3'.D8
# Like 'Sheet 3'!D8 (MS Excel format, LibreOffice Calc can parse it)
"cross-reference": {
"cell-prefix": "",
"cell-suffix": "",
"cell-separator": "",
"sheet-prefix": "$'",
"sheet-suffix": "'.",
"sheet-prefix": "'",
"sheet-suffix": "'!",
"row-first": False,
"sheet-first": True
},
Expand Down
4 changes: 2 additions & 2 deletions portable_spreadsheet/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def _excel_write_variables_to_sheet(workbook: object,
variables_sheet.write(variable_row_position,
offset_columns + 0,
var_n)
if var_v['cell'].computational_variable:
if not var_v['cell'].computational_variable:
# In the case that variable contains only the value
variables_sheet.write(
variable_row_position,
Expand All @@ -231,7 +231,7 @@ def _excel_write_variables_to_sheet(workbook: object,
variables_sheet.write_formula(
variable_row_position,
offset_columns + 1,
var_v['cell'].parse['excel'],
var_v['cell'].parse_variable['excel'],
value=var_v['value'],
cell_format=variable_style
)
Expand Down
13 changes: 10 additions & 3 deletions portable_spreadsheet/sheet_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,16 @@ def set_variable(self,

self.description[name] = description
if isinstance(value, Cell):
self._variables[name] = value
self._variables[name]._is_computational_variable = False
self._variables[name] = Cell.variable(
Cell(None, None, # No position
variable_name=name,
value=value.value,
is_variable=True,
cell_type=CellType.computational,
cell_indices=self.spreadsheet.cell_indices
)
)
self._variables[name]._variable_words = value._constructing_words
else:
self._variables[name] = Cell.variable(
Cell(None, None, # No position
Expand All @@ -469,7 +477,6 @@ def set_variable(self,
cell_indices=self.spreadsheet.cell_indices
)
)
self._variables[name]._is_computational_variable = True
self._variables[name].is_variable = True

def get_variables_dict(self, include_cell: bool = True) -> dict:
Expand Down
6 changes: 5 additions & 1 deletion portable_spreadsheet/word_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,12 +502,14 @@ def aggregation(cell_start: 'Cell',
return instance

@staticmethod
def parse(cell: 'Cell') -> T_word:
def parse(cell: 'Cell', variable_word: bool = False) -> T_word:
"""Parse the cell word. This function is called when the cell should
be inserted to spreadsheet.
Args:
cell (Cell): The cell that is the subject of parsing.
variable_word (bool): If true, variable construction word
is constructed.
Returns:
T_word: Parsed cell.
Expand All @@ -521,6 +523,8 @@ def parse(cell: 'Cell') -> T_word:
elif cell.cell_type == CellType.computational:
# Computational type
words: T_word = copy.deepcopy(cell.constructing_words.words)
if variable_word and cell._variable_words is not None:
words = copy.deepcopy(cell._variable_words.words)
for language in cell.constructing_words.languages:
prefix = GRAMMARS[language]['cells']['operation']['prefix']
suffix = GRAMMARS[language]['cells']['operation']['suffix']
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="portable-spreadsheet",
version="2.1.1",
version="2.1.2",
author="David Salac",
author_email="[email protected]",
description="A simple spreadsheet that keeps tracks of each operation of each cell in defined languages. Logic allows exporting sheets to Excel files (and see how each cell is computed), to the JSON strings with a description of computation of each cell (e. g. in the native language). Other formats, like HTML, CSV and Markdown (MD), are also implemented (user can define own format). It also allows reconstructing behaviours in native Python with NumPy.", # noqa
Expand Down
20 changes: 20 additions & 0 deletions tests/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,26 @@ def test_to_json(self):
computed_parsed_dict: dict = json.loads(self.sheet.to_json())
self.assertDictEqual(expected_parsed_dict, computed_parsed_dict)

def test_variable_serialization(self):
"""Test the serialisation of variables"""
self.sheet.var['var_a'] = 11
self.sheet.var['var_b'] = 22
self.sheet.var['var_c'] = (self.sheet.var['var_a'] +
self.sheet.var['var_b'])
vars_to_dict = self.sheet.to_dictionary()
vars_to_dict = vars_to_dict['table']['variables']
self.assertDictEqual(vars_to_dict, {'var_a': {'value': 11, 'description': None}, 'var_b': {'value': 22, 'description': None}, 'var_c': {'value': 33, 'description': None}}) # noqa
# Test computational variable
self.assertDictEqual(self.sheet.var['var_c'].parse_variable, {'python_numpy': 'var_a+var_b', 'native': "value of variable 'var_a (=11)' + value of variable 'var_b (=22)'", 'excel': '=var_a+var_b'}) # noqa
self.assertDictEqual(self.sheet.var['var_c'].parse, {'excel': '=var_c', 'native': "value of variable 'var_c (=33)'", 'python_numpy': 'var_c'}) # noqa

# Test words of non-computational variables (value-only variables)
self.assertDictEqual(self.sheet.var['var_a'].parse, {'excel': '=var_a', 'native': "value of variable 'var_a (=11)'", 'python_numpy': 'var_a'}) # noqa
self.assertDictEqual(self.sheet.var['var_a'].parse_variable, {'python_numpy': 'var_a', 'excel': '=var_a', 'native': "value of variable 'var_a (=11)'"}) # noqa

self.assertDictEqual(self.sheet.var['var_b'].parse, {'python_numpy': 'var_b', 'native': "value of variable 'var_b (=22)'", 'excel': '=var_b'}) # noqa
self.assertDictEqual(self.sheet.var['var_b'].parse_variable, {'excel': '=var_b', 'python_numpy': 'var_b', 'native': "value of variable 'var_b (=22)'"}) # noqa


class TestSerializationToArrays(unittest.TestCase):
"""Test to_numpy serializer."""
Expand Down

0 comments on commit 661c345

Please sign in to comment.