gnumeric 0.1.0__tar.gz

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.
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: gnumeric
3
+ Version: 0.1.0
4
+ Summary: A python library for reading and writing Gnumeric files
5
+ Author: Michael Lipschultz
6
+ Author-email: Michael Lipschultz <michael.lipschultz@gmail.com>
7
+ License-Expression: GPL-3.0-only
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
16
+ Requires-Dist: lxml>=6.1.1,<7
17
+ Requires-Dist: python-dateutil>=2.9.0.post0,<3
18
+ Requires-Dist: lark>=1.3.1,<2
19
+ Requires-Python: >=3.11, <4
20
+ Project-URL: Homepage, https://github.com/lipschultz/gnumeric-py
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Gnumeric-py
24
+
25
+ A python library for reading and writing [Gnumeric](http://www.gnumeric.org/) files.
26
+
27
+ ## Quick Start
28
+
29
+ Open an existing workbook and explore what's available:
30
+
31
+ ```python
32
+ from gnumeric.workbook import Workbook
33
+
34
+ wb = Workbook.load_workbook('samples/test.gnumeric')
35
+
36
+ # Get the active sheet
37
+ ws = wb.get_active_sheet() # can also use wb.active
38
+
39
+ # Get a sheet by name
40
+ ws_1 = wb.get_sheet_by_name('Sheet1')
41
+
42
+ # Get cell at A1
43
+ cell_a1 = ws['A1']
44
+ cell_a1 = ws[(0, 0)] # zero-indexed (row, column)
45
+
46
+ # Get the value in the cell
47
+ cell_a1.get_value()
48
+ ```
49
+
50
+ ## Unsupported Features
51
+
52
+ Currently, this library does not support:
53
+
54
+ 1. Evaluating almost all expressions
55
+ 2. Graphs
@@ -0,0 +1,33 @@
1
+ # Gnumeric-py
2
+
3
+ A python library for reading and writing [Gnumeric](http://www.gnumeric.org/) files.
4
+
5
+ ## Quick Start
6
+
7
+ Open an existing workbook and explore what's available:
8
+
9
+ ```python
10
+ from gnumeric.workbook import Workbook
11
+
12
+ wb = Workbook.load_workbook('samples/test.gnumeric')
13
+
14
+ # Get the active sheet
15
+ ws = wb.get_active_sheet() # can also use wb.active
16
+
17
+ # Get a sheet by name
18
+ ws_1 = wb.get_sheet_by_name('Sheet1')
19
+
20
+ # Get cell at A1
21
+ cell_a1 = ws['A1']
22
+ cell_a1 = ws[(0, 0)] # zero-indexed (row, column)
23
+
24
+ # Get the value in the cell
25
+ cell_a1.get_value()
26
+ ```
27
+
28
+ ## Unsupported Features
29
+
30
+ Currently, this library does not support:
31
+
32
+ 1. Evaluating almost all expressions
33
+ 2. Graphs
@@ -0,0 +1,8 @@
1
+ {
2
+ "__author__": "Michael Lipschultz",
3
+ "__author_email__": "michael.lipschultz@gmail.com",
4
+ "__license__": "GPL v3",
5
+ "__maintainer_email__": "michael.lipschultz@gmail.com",
6
+ "__url__": "https://github.com/lipschultz/gnumeric-py",
7
+ "__version__": "0.0.1"
8
+ }
@@ -0,0 +1,41 @@
1
+ """
2
+ Gnumeric-py: Reading and writing gnumeric files with python
3
+ Copyright (C) 2017 Michael Lipschultz
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ """
18
+
19
+ import json
20
+ import os
21
+
22
+ try:
23
+ here = os.path.abspath(os.path.dirname(__file__))
24
+ src_file = os.path.join(here, '.constants.json')
25
+ with open(src_file) as src:
26
+ constants = json.load(src)
27
+ __author__ = constants['__author__']
28
+ __author_email__ = constants['__author_email__']
29
+ __license__ = constants['__license__']
30
+ __maintainer_email__ = constants['__maintainer_email__']
31
+ __url__ = constants['__url__']
32
+ __version__ = constants['__version__']
33
+ except IOError:
34
+ # packaged
35
+ pass
36
+
37
+ from gnumeric.workbook import Workbook
38
+
39
+
40
+ def load_workbook(filepath):
41
+ return Workbook.load_workbook(filepath)
@@ -0,0 +1,294 @@
1
+ """
2
+ Gnumeric-py: Reading and writing gnumeric files with python
3
+ Copyright (C) 2017 Michael Lipschultz
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ """
18
+
19
+ import datetime
20
+ from typing import Optional, Union
21
+
22
+ from lxml import etree
23
+
24
+ from gnumeric.exceptions import UnrecognizedCellTypeException
25
+ from gnumeric.expression import Expression
26
+ from gnumeric.utils import RowColReference
27
+
28
+ VALUE_TYPE_EXPR = -10
29
+ VALUE_TYPE_EMPTY = 10
30
+ VALUE_TYPE_BOOLEAN = 20
31
+ VALUE_TYPE_INTEGER = 30
32
+ VALUE_TYPE_FLOAT = 40
33
+ VALUE_TYPE_ERROR = 50
34
+ VALUE_TYPE_STRING = 60
35
+ VALUE_TYPE_CELLRANGE = 70
36
+ VALUE_TYPE_ARRAY = 80
37
+
38
+
39
+ class Cell:
40
+ _instances = {}
41
+
42
+ _BASE_DATETIME = datetime.datetime(1899, 12, 30)
43
+
44
+ def __new__(cls, cell_element, style_region_element, worksheet, ns):
45
+ key = (cell_element, style_region_element, worksheet)
46
+ instance = cls._instances.get(key)
47
+ if not instance:
48
+ instance = super(Cell, cls).__new__(cls)
49
+ instance.__cached_value = None
50
+ instance.__time_cached_value_set = None
51
+ cls._instances[key] = instance
52
+ return instance
53
+
54
+ def __init__(self, cell_element, style_region_element, worksheet, ns):
55
+ self.__cell = cell_element
56
+ self.__style_region = style_region_element
57
+ self.__worksheet = worksheet
58
+ self.__ns = ns
59
+
60
+ def __get_style_element(self):
61
+ elements = self.__style_region.xpath('./gnm:Style', namespaces=self.__ns)
62
+ return elements[0] if elements else None
63
+
64
+ def __set_expression_id(self, expr_id: str) -> None:
65
+ self.__cell.set('ExprID', expr_id)
66
+
67
+ @property
68
+ def worksheet(self):
69
+ """
70
+ The worksheet this cell belongs to.
71
+ """
72
+ return self.__worksheet
73
+
74
+ @property
75
+ def column(self) -> int:
76
+ """
77
+ The column this cell belongs to (0-indexed).
78
+ """
79
+ return int(self.__cell.get('Col'))
80
+
81
+ @property
82
+ def row(self) -> int:
83
+ """
84
+ The row this cell belongs to (0-indexed).
85
+ """
86
+ return int(self.__cell.get('Row'))
87
+
88
+ @property
89
+ def coordinate(self) -> RowColReference:
90
+ """
91
+ The (row, column) of the cell (0-indexed)
92
+ """
93
+ return RowColReference(self.row, self.column)
94
+
95
+ @property
96
+ def text(self) -> Optional[str]:
97
+ """
98
+ Returns the raw value stored in the cell. The text will be `None` if the cell is empty.
99
+ :return: str or `None`
100
+ """
101
+ return self.__cell.text
102
+
103
+ @property
104
+ def value_type(self) -> int:
105
+ """
106
+ Returns the type of value stored in the cell:
107
+ - VALUE_TYPE_EXPR = -10
108
+ - VALUE_TYPE_EMPTY = 10
109
+ - VALUE_TYPE_BOOLEAN = 20
110
+ - VALUE_TYPE_INTEGER = 30
111
+ - VALUE_TYPE_FLOAT = 40
112
+ - VALUE_TYPE_ERROR = 50
113
+ - VALUE_TYPE_STRING = 60
114
+ - VALUE_TYPE_CELLRANGE = 70
115
+ - VALUE_TYPE_ARRAY = 80
116
+ """
117
+ value_type = self.__cell.get('ValueType')
118
+ if value_type is not None:
119
+ return int(value_type)
120
+ elif self.__cell.get('ExprID') is not None or self.text.startswith('='):
121
+ return VALUE_TYPE_EXPR
122
+ else:
123
+ raise UnrecognizedCellTypeException(
124
+ 'Cell is: "' + str(etree.tostring(self.__cell)) + '"'
125
+ )
126
+
127
+ def is_datetime(self) -> bool:
128
+ return (
129
+ self.value_type == VALUE_TYPE_FLOAT
130
+ and self.__cell.get('ValueFormat') == 'yyyy-mmm-dd'
131
+ )
132
+
133
+ def __set_type(self, value_type: int):
134
+ if value_type == VALUE_TYPE_EXPR:
135
+ if 'ValueType' in self.__cell.keys():
136
+ self.__cell.attrib.pop('ValueType')
137
+ else:
138
+ self.__cell.set('ValueType', str(value_type))
139
+
140
+ def get_value(
141
+ self, *, compute_expression: bool = False
142
+ ) -> Union[bool, int, float, Expression, str]:
143
+ """
144
+ Gets the value stored in the cell, converted into the appropriate Python datatype when possible.
145
+
146
+ If the cell is an expression: If `compute_expression` is True, the the result of the expression
147
+ is returned, otherwise an Expression object is returned.
148
+ """
149
+ value = self.text
150
+ if self.value_type == VALUE_TYPE_BOOLEAN:
151
+ return value.lower() == 'true'
152
+ elif self.value_type == VALUE_TYPE_INTEGER:
153
+ return int(value)
154
+ elif self.value_type == VALUE_TYPE_FLOAT:
155
+ return float(value)
156
+ elif self.value_type == VALUE_TYPE_EXPR:
157
+ expression = Expression(self.__cell.get('ExprID'), self.__worksheet, self)
158
+ if not compute_expression:
159
+ return expression
160
+ else:
161
+ if self.__cached_value is None:
162
+ self.__cached_value = 0
163
+ self.__cached_value = expression.value
164
+ return self.__cached_value
165
+ else:
166
+ return value
167
+
168
+ def set_value(self, value, *, value_type: str = 'infer') -> None:
169
+ """
170
+ Sets the value stored in the cell.
171
+
172
+ If `value_type` is:
173
+ - one of the `VALUE_TYPE_` constants, then that value type will be used
174
+ - ``keep'`, then the cell will keep its type
175
+ - `'infer'`, then it tries to guess the type based on the value being set:
176
+ - if `value` is of type `bool`, then `VALUE_TYPE_BOOLEAN`
177
+ - if `value` is of type `int`, then `VALUE_TYPE_INTEGER`
178
+ - if `value` is of type `float`, then `VALUE_TYPE_FLOAT`
179
+ - if `value` is an empty string or `None`, then `VALUE_TYPE_EMPTY`
180
+ - if `value` is a string that starts with `=` or is an `Expression` object, then `VALUE_TYPE_EXPR`
181
+ - if `value` is anything else, then `VALUE_TYPE_STRING`
182
+
183
+ The default `value_type` is `'infer'`.
184
+
185
+ Warning: This method does no type checking, so it is possible to save a string into a cell whose type is
186
+ `VALUE_TYPE_INTEGER`. This could result in problems when opening the workbook in Gnumeric.
187
+ """
188
+ val_types = {
189
+ bool: VALUE_TYPE_BOOLEAN,
190
+ int: VALUE_TYPE_INTEGER,
191
+ float: VALUE_TYPE_FLOAT,
192
+ }
193
+ if value_type == 'infer':
194
+ if type(value) in val_types:
195
+ value_type = val_types[type(value)]
196
+ elif value in ('', None):
197
+ value_type = VALUE_TYPE_EMPTY
198
+ elif isinstance(value, Expression) or value[0] == '=':
199
+ value_type = VALUE_TYPE_EXPR
200
+ elif self.value_type in (
201
+ VALUE_TYPE_EMPTY,
202
+ VALUE_TYPE_BOOLEAN,
203
+ VALUE_TYPE_INTEGER,
204
+ VALUE_TYPE_FLOAT,
205
+ VALUE_TYPE_ERROR,
206
+ ):
207
+ value_type = VALUE_TYPE_STRING
208
+ else:
209
+ value_type = self.value_type
210
+ elif value_type == 'keep':
211
+ value_type = self.value_type
212
+
213
+ if value_type == VALUE_TYPE_BOOLEAN:
214
+ self.__cell.text = str(bool(value)).upper()
215
+ elif value_type == VALUE_TYPE_EMPTY:
216
+ self.__cell.text = None
217
+ elif value_type == VALUE_TYPE_EXPR and isinstance(value, Expression):
218
+ if self.__worksheet != value.worksheet:
219
+ raise NotImplementedError(
220
+ 'Copying expression to different worksheet is not yet supported'
221
+ ) # TODO
222
+
223
+ expr_id = str(value.id)
224
+ if (
225
+ expr_id not in self.__worksheet.get_expression_map()
226
+ and value.id is None
227
+ ):
228
+ expr_id = str(
229
+ max(int(k) for k in self.__worksheet.get_expression_map()) + 1
230
+ )
231
+
232
+ if len(value.get_all_cells()) == 1 and value.get_originating_cell() == self:
233
+ # copying expression over itself, so don't add it to cells using this expression
234
+ self.__cell.text = value.value
235
+ else:
236
+ # the expression is shared, so use the expression id
237
+ if len(value.get_all_cells()) == 1:
238
+ value.get_originating_cell().__set_expression_id(expr_id)
239
+ self.__cell.text = None
240
+ self.__set_expression_id(expr_id)
241
+ else:
242
+ self.__cell.text = str(value)
243
+
244
+ self.__set_type(value_type)
245
+ self.__cached_value = self.get_value(compute_expression=True)
246
+
247
+ value = property(
248
+ get_value,
249
+ set_value,
250
+ doc='Get or set the value in the cell, converted into the correct type.',
251
+ )
252
+
253
+ @property
254
+ def result(self):
255
+ """
256
+ Gets the result of the cell. For expressions, it returns the result of the expression. For literals, it returns the literal.
257
+ """
258
+ value = self.get_value(compute_expression=True)
259
+ if value is None:
260
+ value = 0
261
+ elif self.is_datetime():
262
+ value = self._BASE_DATETIME + datetime.timedelta(days=value)
263
+ return value
264
+
265
+ @property
266
+ def text_format(self) -> str:
267
+ """
268
+ The format string used to format the text in the cell for display. This is the "Number Format" in Gnumeric.
269
+ """
270
+ return str(
271
+ self.__style_region.xpath('./gnm:Style/@Format', namespaces=self.__ns)[0]
272
+ )
273
+
274
+ def __str__(self) -> str:
275
+ return repr(self.value)
276
+
277
+ def __repr__(self) -> str:
278
+ return 'Cell[%s, (%d, %d), ws="%s"]' % (
279
+ str(self),
280
+ self.row,
281
+ self.column,
282
+ self.__worksheet.title,
283
+ )
284
+
285
+ def __eq__(self, other) -> bool:
286
+ return (
287
+ isinstance(other, Cell)
288
+ and self.__worksheet == other.__worksheet
289
+ and self.row == other.row
290
+ and self.column == other.column
291
+ )
292
+
293
+ def __hash__(self) -> int:
294
+ return hash(self.__cell)
@@ -0,0 +1,24 @@
1
+ import enum
2
+
3
+
4
+ class EvaluationError(enum.Enum):
5
+ DIV0 = '#DIV/0!'
6
+ VALUE = '#VALUE!'
7
+ NA = '#N/A'
8
+ NAME = '#NAME?'
9
+ NUM = '#NUM!' # =10000000000^1000000000
10
+ REF = '#REF!'
11
+ NULL = (
12
+ '#NULL!' # occurs when the intersection of two areas don't actually intersect
13
+ )
14
+
15
+
16
+ class ExpressionEvaluationException(Exception):
17
+ """
18
+ Evaulating the expression has failed.
19
+ """
20
+
21
+ def __init__(self, error: EvaluationError, msg=None):
22
+ msg = msg or error.value
23
+ super().__init__(msg)
24
+ self.error = error
@@ -0,0 +1,49 @@
1
+ """
2
+ Gnumeric-py: Reading and writing gnumeric files with python
3
+ Copyright (C) 2017 Michael Lipschultz
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ """
18
+
19
+
20
+ class DuplicateTitleException(Exception):
21
+ """
22
+ A workbook cannot contain multiple sheets with the same name/title.
23
+ """
24
+
25
+ def __init__(self, msg):
26
+ super().__init__(msg)
27
+
28
+
29
+ class WrongWorkbookException(Exception):
30
+ """
31
+ A sheet or cell from one workbook being using in another workbook.
32
+ """
33
+
34
+ def __init__(self, msg):
35
+ super().__init__(msg)
36
+
37
+
38
+ class UnsupportedOperationException(Exception):
39
+ def __init__(self, msg):
40
+ super().__init__(msg)
41
+
42
+
43
+ class UnrecognizedCellTypeException(Exception):
44
+ """
45
+ The type of cell cannot be determined.
46
+ """
47
+
48
+ def __init__(self, msg):
49
+ super().__init__(msg)
@@ -0,0 +1,151 @@
1
+ """
2
+ Gnumeric-py: Reading and writing gnumeric files with python
3
+ Copyright (C) 2017 Michael Lipschultz
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ """
18
+
19
+ from typing import Set, Union
20
+
21
+ from gnumeric import expression_evaluation, utils
22
+ from gnumeric.evaluation_errors import EvaluationError
23
+
24
+
25
+ class Expression:
26
+ # TODO: what to do if originating cell's text changes or is deleted?
27
+
28
+ def __init__(self, id, worksheet, cell):
29
+ """
30
+ :param cell: The cell this Expression was created from. It could be the originating cell or just a cell that
31
+ uses this expression. It's used when `id` is `None` (i.e. the expression isn't shared between cells).
32
+ """
33
+ self.__exprid = id
34
+ self.__worksheet = worksheet
35
+ self.__cell = cell
36
+
37
+ def __get_raw_originating_cell(self):
38
+ """
39
+ Returns a (int, int, str) tuple, where the values are (row, column, text of the cell).
40
+ """
41
+ if self.__exprid is not None:
42
+ coords, text = self.__worksheet.get_expression_map()[self.__exprid]
43
+ return int(coords[0]), int(coords[1]), text
44
+ else:
45
+ return self.__cell.row, self.__cell.column, self.__cell.text
46
+
47
+ @property
48
+ def id(self):
49
+ """
50
+ The expression id used to uniquely identify the expression within the sheet. This will be `None` if the
51
+ expression isn't shared between cells.
52
+ """
53
+ return self.__exprid
54
+
55
+ @property
56
+ def original_text(self) -> str:
57
+ """
58
+ Returns the text of the expression, with cell references from the perspective of the cell where the expression
59
+ is stored (i.e. the original cell).
60
+ """
61
+ return self.__get_raw_originating_cell()[2]
62
+
63
+ @property
64
+ def text(self):
65
+ """
66
+ Returns the text of the exprsesion, with cell references updated to be from the perspective of the cell using the expression.
67
+ """
68
+ # TODO: fix this to actually return what it's supposed to
69
+ raise NotImplementedError
70
+
71
+ @property
72
+ def reference_coordinate_offset(self) -> utils.RowColReference:
73
+ """
74
+ The (row, col) offset to translate the original coordinates into the coordinates based at the current cell.
75
+ """
76
+ original_coordinates = self.get_originating_cell_coordinate()
77
+ current_coordinates = self.__cell.coordinate
78
+ return utils.RowColReference(
79
+ current_coordinates[0] - original_coordinates[0],
80
+ current_coordinates[1] - original_coordinates[1],
81
+ )
82
+
83
+ @property
84
+ def value(self):
85
+ """
86
+ Returns the result of the expression's evaluation.
87
+ """
88
+ return expression_evaluation.evaluate(self.original_text, self.__cell)
89
+
90
+ @property
91
+ def worksheet(self):
92
+ """
93
+ The worksheet this expression is created in.
94
+ """
95
+ return self.__worksheet
96
+
97
+ def get_originating_cell_coordinate(
98
+ self, representation_format='index'
99
+ ) -> Union[utils.RowColReference, str]:
100
+ """
101
+ Returns the cell coordinate for the cell Gnumeric is using to store the expression.
102
+
103
+ :param representation_format: For spreadsheet notation, use `'spreadsheet'`, for 0-indexed (row, column)
104
+ notation, use 'index' (default).
105
+ :return: A `str` if `representation_format` is `'spreadsheet'` and a tuple of ints `(int, int)` if 'index'.
106
+ """
107
+ row, col = self.__get_raw_originating_cell()[:2]
108
+ if representation_format == 'index':
109
+ return utils.RowColReference(row, col)
110
+ elif representation_format == 'spreadsheet':
111
+ return utils.coordinate_to_spreadsheet(row, col)
112
+
113
+ def get_originating_cell(self):
114
+ """
115
+ Returns the cell Gnumeric is using to store the expression.
116
+ """
117
+ return self.__worksheet.cell(
118
+ *self.get_originating_cell_coordinate(), create=False
119
+ )
120
+
121
+ def get_all_cells(self, sort=False):
122
+ """
123
+ Returns a list of all cells using this expression.
124
+
125
+ Use `sort` to specify whether the cells should be sorted. If `False` (default), then no sorting will take
126
+ place. If `sort` is `"row"`, then sorting will occur by row first, then by column within each row. If `sort`
127
+ is `"column"`, then the opposite will happen: first sort by column, then by row within each column.
128
+ """
129
+ if self.__exprid is None:
130
+ return [self.__cell]
131
+ else:
132
+ return self.__worksheet.get_all_cells_with_expression(
133
+ self.__exprid, sort=sort
134
+ )
135
+
136
+ def get_referenced_cells(self) -> Union[Set, EvaluationError]:
137
+ return expression_evaluation.get_referenced_cells(
138
+ self.original_text, self.__cell
139
+ )
140
+
141
+ def __str__(self):
142
+ return self.original_text
143
+
144
+ def __repr__(self):
145
+ return 'Expression(id=%s, text="%s", ws=%s, cell=(%d, %d))' % (
146
+ self.id,
147
+ self.original_text,
148
+ self.__worksheet,
149
+ self.__cell.row,
150
+ self.__cell.column,
151
+ )