gridcalc 0.1.1__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.
gridcalc-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shakeeb Alireza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.4
2
+ Name: gridcalc
3
+ Version: 0.1.1
4
+ Summary: A terminal spreadsheet powered by Python formulas
5
+ Keywords: spreadsheet,terminal,tui,curses,calculator,visicalc
6
+ Author: Shakeeb Alireza
7
+ Author-email: Shakeeb Alireza <shakfu@users.noreply.github.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console :: Curses
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
22
+ Classifier: Topic :: Utilities
23
+ Classifier: Typing :: Typed
24
+ Requires-Dist: tomli>=1.0 ; python_full_version < '3.11'
25
+ Requires-Python: >=3.10
26
+ Project-URL: Homepage, https://github.com/shakfu/gridcalc
27
+ Project-URL: Repository, https://github.com/shakfu/gridcalc
28
+ Project-URL: Issues, https://github.com/shakfu/gridcalc/issues
29
+ Description-Content-Type: text/markdown
30
+
31
+ # gridcalc
32
+
33
+ [![PyPI](https://img.shields.io/pypi/v/gridcalc)](https://pypi.org/project/gridcalc/)
34
+ [![Python](https://img.shields.io/pypi/pyversions/gridcalc)](https://pypi.org/project/gridcalc/)
35
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
36
+
37
+ A terminal spreadsheet powered by Python formulas. Based on Serge Zaitsev's [kalk](https://github.com/zserge/kalk), reimplemented in pure Python from [pktcalc](https://github.com/sa/pktcalc).
38
+
39
+ Uses Python's `eval()` for formula evaluation. Reads and writes JSON. File-compatible with pktcalc.
40
+
41
+ ```sh
42
+ $ gridcalc budget.json
43
+ ```
44
+
45
+ ## Install
46
+
47
+ From PyPI (requires Python 3.10+):
48
+
49
+ ```sh
50
+ pip install gridcalc
51
+ ```
52
+
53
+ Or with [uv](https://docs.astral.sh/uv/):
54
+
55
+ ```sh
56
+ uv tool install gridcalc
57
+ ```
58
+
59
+ Then run:
60
+
61
+ ```sh
62
+ gridcalc # new spreadsheet
63
+ gridcalc budget.json # open a file
64
+ ```
65
+
66
+ ### From source
67
+
68
+ ```sh
69
+ git clone https://github.com/shakfu/gridcalc.git
70
+ cd gridcalc
71
+ uv run gridcalc
72
+ ```
73
+
74
+ ## File format
75
+
76
+ Spreadsheets are stored as JSON:
77
+
78
+ ```json
79
+ {
80
+ "code": "def margin(rev, cost):\n return (rev - cost) / rev * 100\n",
81
+ "names": {
82
+ "revenue": "A1:A12",
83
+ "costs": "B1:B12"
84
+ },
85
+ "cells": [
86
+ ["Revenue", "Cost", "Margin"],
87
+ [1000, 600, "=margin(A1, B1)"],
88
+ [1200, 700, "=margin(A2, B2)"]
89
+ ],
90
+ "format": {
91
+ "width": 10
92
+ }
93
+ }
94
+ ```
95
+
96
+ - **cells**: 2D array of cell values (numbers, strings, formulas, or null)
97
+ - **code** (optional): Python code executed before formulas (functions, imports, constants)
98
+ - **names** (optional): named ranges mapping names to cell ranges
99
+ - **format** (optional): display settings (currently only `width`)
100
+
101
+ ## Usage
102
+
103
+ Arrow keys navigate. Type a number or `=` to enter data. Formulas start
104
+ with `=` and are Python expressions. Anything else is a label.
105
+
106
+ Press `:` for the command line (vim-style):
107
+
108
+ :q Quit
109
+ :q! Force quit (no save prompt)
110
+ :w [file] Save
111
+ :wq [file] Save and quit
112
+ :e Edit code block in $EDITOR
113
+ :o [file] Open file
114
+ :b Blank current cell
115
+ :clear Clear entire sheet
116
+ :f <fmt> Format/style cell (b u i L R I G D $ % * or Python spec)
117
+ :gf <fmt> Set global format
118
+ :width <n> Set column width (4-40)
119
+ :dr Delete row
120
+ :dc Delete column
121
+ :ir Insert row
122
+ :ic Insert column
123
+ :m Move row/column (arrow keys to drag)
124
+ :r Replicate (copy with relative refs)
125
+ :name <n> [range] Define named range
126
+ :names List named ranges
127
+ :unname <n> Remove named range
128
+ :tv/:th/:tb/:tn Lock/unlock title rows/columns
129
+
130
+ Other keys:
131
+
132
+ > Go to cell (type reference)
133
+ ! Force recalculation
134
+ " Enter label
135
+ Backspace Clear cell
136
+ Tab Next column
137
+ Enter Next row
138
+ Home Jump to A1
139
+ Ctrl-B Toggle bold
140
+ Ctrl-U Toggle underline
141
+ Ctrl-Z Undo
142
+ Ctrl-Y Redo
143
+ Ctrl-C Quit
144
+
145
+ ## Formulas
146
+
147
+ Formulas are Python expressions prefixed with `=`. Cell references like
148
+ `A1`, `B3`, `AA10` are available as variables.
149
+
150
+ =A1 + B1 * 2
151
+ =(A1 + A2) / 2
152
+ =A1 ** 2
153
+ =SQRT(A3 + A2)
154
+
155
+ ### Range syntax
156
+
157
+ Use `:` to reference a range of cells. Ranges expand into arrays (Vec)
158
+ that support element-wise arithmetic.
159
+
160
+ =SUM(A1:A10)
161
+ =AVG(B1:B3)
162
+ =SUM(A1:A3 * B1:B3)
163
+
164
+ ### Named ranges
165
+
166
+ Define a name for a cell range with `:name`, or in the JSON file's
167
+ `names` field. Names are injected as arrays and can be used directly in
168
+ formulas.
169
+
170
+ =SUM(revenue)
171
+ =SUM(revenue - costs)
172
+ =MAX(revenue)
173
+ =sum([x**2 for x in revenue])
174
+
175
+ ### Custom functions
176
+
177
+ Use `:e` to open the code block in `$EDITOR`. The editor must block
178
+ until the file is closed (e.g., `vim`, `nano`, or `subl -w` for Sublime
179
+ Text). Define Python functions, import modules, set constants:
180
+
181
+ ```python
182
+ import statistics
183
+
184
+ def margin(rev, cost):
185
+ return (rev - cost) / rev * 100
186
+
187
+ def compound(principal, rate, years):
188
+ return principal * (1 + rate) ** years
189
+
190
+ TAX_RATE = 0.21
191
+ ```
192
+
193
+ Then use them in formulas: `=margin(A1, B1)`, `=compound(1000, 0.05, 10)`.
194
+
195
+ ### Built-in functions
196
+
197
+ SUM(x) Sum of array or scalar
198
+ AVG(x) Average
199
+ MIN(x) Minimum
200
+ MAX(x) Maximum
201
+ COUNT(x) Number of elements
202
+ ABS(x) Absolute value (element-wise for arrays)
203
+ SQRT(x) Square root (element-wise for arrays)
204
+ INT(x) Truncate to integer (element-wise for arrays)
205
+
206
+ Math functions are preloaded: `sin`, `cos`, `tan`, `exp`, `log`,
207
+ `log2`, `log10`, `floor`, `ceil`, `pi`, `e`, `inf`. The `math` module
208
+ is also available for anything else (`=math.factorial(10)`).
209
+
210
+ Python builtins like `sum`, `min`, `max`, `abs`, `len` also work.
211
+
212
+ ### Arrays
213
+
214
+ A formula can return an array. The cell displays the first element and
215
+ the count, e.g. `3.0[12]`. The full array is shown in the status bar.
216
+ Element-wise arithmetic works between arrays and scalars:
217
+
218
+ =revenue * 1.1
219
+ =revenue + costs
220
+
221
+ ### Cell references
222
+
223
+ References adjust automatically on replicate, insert, and delete.
224
+ Use `$` for absolute references: `$A$1` (fixed), `$A1` (fixed column),
225
+ `A$1` (fixed row).
226
+
227
+ ## Formatting
228
+
229
+ Use `:f` to set the display format or style of a cell. All formats
230
+ and styles are persisted when saving.
231
+
232
+ ### Text styles
233
+
234
+ Toggle with `:f` or keyboard shortcuts. Styles can be combined
235
+ in a single command:
236
+
237
+ :f b Toggle bold (also Ctrl-B)
238
+ :f u Toggle underline (also Ctrl-U)
239
+ :f i Toggle italic
240
+ :f bi Toggle bold + italic
241
+ :f bui Toggle bold + underline + italic
242
+
243
+ ### Number formats
244
+
245
+ :f $ Dollar (2 decimal places)
246
+ :f % Percentage (value * 100, 2 decimal places)
247
+ :f I Integer (truncate decimals)
248
+ :f * Bar chart (asterisks proportional to value)
249
+ :f L Left-align
250
+ :f R Right-align
251
+ :f G General (default)
252
+ :f D Use global format
253
+
254
+ Use `:gf` to set the global default format for all cells.
255
+
256
+ ### Python format specs
257
+
258
+ For more control, pass any Python format specification:
259
+
260
+ :f ,.2f 1,234.50 (comma thousands, 2 decimals)
261
+ :f ,.0f 1,234,567 (comma thousands, no decimals)
262
+ :f .1% 15.7% (percentage with 1 decimal)
263
+ :f .4f 3.1416 (fixed 4 decimal places)
264
+ :f .2e 1.23e+04 (scientific notation)
265
+
266
+ These use Python's `format()` builtin. Any valid
267
+ [format spec](https://docs.python.org/3/library/string.html#format-specification-mini-language)
268
+ works.
269
+
270
+ ## Development
271
+
272
+ ```sh
273
+ make test # run tests
274
+ make lint # ruff check
275
+ make format # ruff format
276
+ make typecheck # mypy
277
+ make qa # lint + typecheck + test + format
278
+ ```
279
+
280
+ ### Publishing
281
+
282
+ ```sh
283
+ make check # build and check dist with twine
284
+ make publish-test # upload to TestPyPI
285
+ make publish # upload to PyPI
286
+ ```
287
+
288
+ ## License
289
+
290
+ MIT
@@ -0,0 +1,260 @@
1
+ # gridcalc
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/gridcalc)](https://pypi.org/project/gridcalc/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/gridcalc)](https://pypi.org/project/gridcalc/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ A terminal spreadsheet powered by Python formulas. Based on Serge Zaitsev's [kalk](https://github.com/zserge/kalk), reimplemented in pure Python from [pktcalc](https://github.com/sa/pktcalc).
8
+
9
+ Uses Python's `eval()` for formula evaluation. Reads and writes JSON. File-compatible with pktcalc.
10
+
11
+ ```sh
12
+ $ gridcalc budget.json
13
+ ```
14
+
15
+ ## Install
16
+
17
+ From PyPI (requires Python 3.10+):
18
+
19
+ ```sh
20
+ pip install gridcalc
21
+ ```
22
+
23
+ Or with [uv](https://docs.astral.sh/uv/):
24
+
25
+ ```sh
26
+ uv tool install gridcalc
27
+ ```
28
+
29
+ Then run:
30
+
31
+ ```sh
32
+ gridcalc # new spreadsheet
33
+ gridcalc budget.json # open a file
34
+ ```
35
+
36
+ ### From source
37
+
38
+ ```sh
39
+ git clone https://github.com/shakfu/gridcalc.git
40
+ cd gridcalc
41
+ uv run gridcalc
42
+ ```
43
+
44
+ ## File format
45
+
46
+ Spreadsheets are stored as JSON:
47
+
48
+ ```json
49
+ {
50
+ "code": "def margin(rev, cost):\n return (rev - cost) / rev * 100\n",
51
+ "names": {
52
+ "revenue": "A1:A12",
53
+ "costs": "B1:B12"
54
+ },
55
+ "cells": [
56
+ ["Revenue", "Cost", "Margin"],
57
+ [1000, 600, "=margin(A1, B1)"],
58
+ [1200, 700, "=margin(A2, B2)"]
59
+ ],
60
+ "format": {
61
+ "width": 10
62
+ }
63
+ }
64
+ ```
65
+
66
+ - **cells**: 2D array of cell values (numbers, strings, formulas, or null)
67
+ - **code** (optional): Python code executed before formulas (functions, imports, constants)
68
+ - **names** (optional): named ranges mapping names to cell ranges
69
+ - **format** (optional): display settings (currently only `width`)
70
+
71
+ ## Usage
72
+
73
+ Arrow keys navigate. Type a number or `=` to enter data. Formulas start
74
+ with `=` and are Python expressions. Anything else is a label.
75
+
76
+ Press `:` for the command line (vim-style):
77
+
78
+ :q Quit
79
+ :q! Force quit (no save prompt)
80
+ :w [file] Save
81
+ :wq [file] Save and quit
82
+ :e Edit code block in $EDITOR
83
+ :o [file] Open file
84
+ :b Blank current cell
85
+ :clear Clear entire sheet
86
+ :f <fmt> Format/style cell (b u i L R I G D $ % * or Python spec)
87
+ :gf <fmt> Set global format
88
+ :width <n> Set column width (4-40)
89
+ :dr Delete row
90
+ :dc Delete column
91
+ :ir Insert row
92
+ :ic Insert column
93
+ :m Move row/column (arrow keys to drag)
94
+ :r Replicate (copy with relative refs)
95
+ :name <n> [range] Define named range
96
+ :names List named ranges
97
+ :unname <n> Remove named range
98
+ :tv/:th/:tb/:tn Lock/unlock title rows/columns
99
+
100
+ Other keys:
101
+
102
+ > Go to cell (type reference)
103
+ ! Force recalculation
104
+ " Enter label
105
+ Backspace Clear cell
106
+ Tab Next column
107
+ Enter Next row
108
+ Home Jump to A1
109
+ Ctrl-B Toggle bold
110
+ Ctrl-U Toggle underline
111
+ Ctrl-Z Undo
112
+ Ctrl-Y Redo
113
+ Ctrl-C Quit
114
+
115
+ ## Formulas
116
+
117
+ Formulas are Python expressions prefixed with `=`. Cell references like
118
+ `A1`, `B3`, `AA10` are available as variables.
119
+
120
+ =A1 + B1 * 2
121
+ =(A1 + A2) / 2
122
+ =A1 ** 2
123
+ =SQRT(A3 + A2)
124
+
125
+ ### Range syntax
126
+
127
+ Use `:` to reference a range of cells. Ranges expand into arrays (Vec)
128
+ that support element-wise arithmetic.
129
+
130
+ =SUM(A1:A10)
131
+ =AVG(B1:B3)
132
+ =SUM(A1:A3 * B1:B3)
133
+
134
+ ### Named ranges
135
+
136
+ Define a name for a cell range with `:name`, or in the JSON file's
137
+ `names` field. Names are injected as arrays and can be used directly in
138
+ formulas.
139
+
140
+ =SUM(revenue)
141
+ =SUM(revenue - costs)
142
+ =MAX(revenue)
143
+ =sum([x**2 for x in revenue])
144
+
145
+ ### Custom functions
146
+
147
+ Use `:e` to open the code block in `$EDITOR`. The editor must block
148
+ until the file is closed (e.g., `vim`, `nano`, or `subl -w` for Sublime
149
+ Text). Define Python functions, import modules, set constants:
150
+
151
+ ```python
152
+ import statistics
153
+
154
+ def margin(rev, cost):
155
+ return (rev - cost) / rev * 100
156
+
157
+ def compound(principal, rate, years):
158
+ return principal * (1 + rate) ** years
159
+
160
+ TAX_RATE = 0.21
161
+ ```
162
+
163
+ Then use them in formulas: `=margin(A1, B1)`, `=compound(1000, 0.05, 10)`.
164
+
165
+ ### Built-in functions
166
+
167
+ SUM(x) Sum of array or scalar
168
+ AVG(x) Average
169
+ MIN(x) Minimum
170
+ MAX(x) Maximum
171
+ COUNT(x) Number of elements
172
+ ABS(x) Absolute value (element-wise for arrays)
173
+ SQRT(x) Square root (element-wise for arrays)
174
+ INT(x) Truncate to integer (element-wise for arrays)
175
+
176
+ Math functions are preloaded: `sin`, `cos`, `tan`, `exp`, `log`,
177
+ `log2`, `log10`, `floor`, `ceil`, `pi`, `e`, `inf`. The `math` module
178
+ is also available for anything else (`=math.factorial(10)`).
179
+
180
+ Python builtins like `sum`, `min`, `max`, `abs`, `len` also work.
181
+
182
+ ### Arrays
183
+
184
+ A formula can return an array. The cell displays the first element and
185
+ the count, e.g. `3.0[12]`. The full array is shown in the status bar.
186
+ Element-wise arithmetic works between arrays and scalars:
187
+
188
+ =revenue * 1.1
189
+ =revenue + costs
190
+
191
+ ### Cell references
192
+
193
+ References adjust automatically on replicate, insert, and delete.
194
+ Use `$` for absolute references: `$A$1` (fixed), `$A1` (fixed column),
195
+ `A$1` (fixed row).
196
+
197
+ ## Formatting
198
+
199
+ Use `:f` to set the display format or style of a cell. All formats
200
+ and styles are persisted when saving.
201
+
202
+ ### Text styles
203
+
204
+ Toggle with `:f` or keyboard shortcuts. Styles can be combined
205
+ in a single command:
206
+
207
+ :f b Toggle bold (also Ctrl-B)
208
+ :f u Toggle underline (also Ctrl-U)
209
+ :f i Toggle italic
210
+ :f bi Toggle bold + italic
211
+ :f bui Toggle bold + underline + italic
212
+
213
+ ### Number formats
214
+
215
+ :f $ Dollar (2 decimal places)
216
+ :f % Percentage (value * 100, 2 decimal places)
217
+ :f I Integer (truncate decimals)
218
+ :f * Bar chart (asterisks proportional to value)
219
+ :f L Left-align
220
+ :f R Right-align
221
+ :f G General (default)
222
+ :f D Use global format
223
+
224
+ Use `:gf` to set the global default format for all cells.
225
+
226
+ ### Python format specs
227
+
228
+ For more control, pass any Python format specification:
229
+
230
+ :f ,.2f 1,234.50 (comma thousands, 2 decimals)
231
+ :f ,.0f 1,234,567 (comma thousands, no decimals)
232
+ :f .1% 15.7% (percentage with 1 decimal)
233
+ :f .4f 3.1416 (fixed 4 decimal places)
234
+ :f .2e 1.23e+04 (scientific notation)
235
+
236
+ These use Python's `format()` builtin. Any valid
237
+ [format spec](https://docs.python.org/3/library/string.html#format-specification-mini-language)
238
+ works.
239
+
240
+ ## Development
241
+
242
+ ```sh
243
+ make test # run tests
244
+ make lint # ruff check
245
+ make format # ruff format
246
+ make typecheck # mypy
247
+ make qa # lint + typecheck + test + format
248
+ ```
249
+
250
+ ### Publishing
251
+
252
+ ```sh
253
+ make check # build and check dist with twine
254
+ make publish-test # upload to TestPyPI
255
+ make publish # upload to PyPI
256
+ ```
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,71 @@
1
+
2
+
3
+ [project]
4
+ name = "gridcalc"
5
+ version = "0.1.1"
6
+ description = "A terminal spreadsheet powered by Python formulas"
7
+ readme = "README.md"
8
+ requires-python = ">=3.10"
9
+ license = "MIT"
10
+ license-files = ["LICENSE"]
11
+ authors = [
12
+ { name = "Shakeeb Alireza", email = "shakfu@users.noreply.github.com" }
13
+ ]
14
+ keywords = ["spreadsheet", "terminal", "tui", "curses", "calculator", "visicalc"]
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Environment :: Console :: Curses",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: End Users/Desktop",
20
+ "Operating System :: POSIX",
21
+ "Operating System :: MacOS",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Office/Business :: Financial :: Spreadsheet",
28
+ "Topic :: Utilities",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = [
32
+ "tomli>=1.0; python_version < '3.11'",
33
+ ]
34
+
35
+ [dependency-groups]
36
+ dev = [
37
+ "mypy>=1.19.1",
38
+ "pytest",
39
+ "ruff>=0.15.7",
40
+ "twine>=6.2.0",
41
+ "build>=1.0",
42
+ ]
43
+
44
+ [project.scripts]
45
+ gridcalc = "gridcalc.tui:main"
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/shakfu/gridcalc"
49
+ Repository = "https://github.com/shakfu/gridcalc"
50
+ Issues = "https://github.com/shakfu/gridcalc/issues"
51
+
52
+ [build-system]
53
+ requires = ["uv_build>=0.11.2,<0.12"]
54
+ build-backend = "uv_build"
55
+
56
+ [tool.ruff]
57
+ target-version = "py310"
58
+ line-length = 100
59
+
60
+ [tool.ruff.lint]
61
+ select = ["E", "F", "W", "I", "UP", "B", "SIM", "S"]
62
+ ignore = ["S307", "S603", "S605", "S108", "S102", "S110"]
63
+
64
+ [tool.ruff.lint.per-file-ignores]
65
+ "tests/**" = ["S101"]
66
+
67
+ [tool.mypy]
68
+ python_version = "3.10"
69
+ strict = true
70
+ warn_return_any = true
71
+ warn_unused_configs = true
@@ -0,0 +1,3 @@
1
+ """gridcalc -- a terminal spreadsheet."""
2
+
3
+ __version__ = "0.1.1"
@@ -0,0 +1,11 @@
1
+ import os
2
+ import sys
3
+
4
+ # Support both `python -m gridcalc` (relative import) and direct execution
5
+ if __package__:
6
+ from .tui import main
7
+ else:
8
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
9
+ from gridcalc.tui import main
10
+
11
+ main()