hekatan 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.
- hekatan-0.1.0/LICENSE +21 -0
- hekatan-0.1.0/PKG-INFO +114 -0
- hekatan-0.1.0/README.md +86 -0
- hekatan-0.1.0/pyproject.toml +38 -0
- hekatan-0.1.0/setup.cfg +4 -0
- hekatan-0.1.0/src/hekatan/__init__.py +32 -0
- hekatan-0.1.0/src/hekatan/display.py +473 -0
- hekatan-0.1.0/src/hekatan.egg-info/PKG-INFO +114 -0
- hekatan-0.1.0/src/hekatan.egg-info/SOURCES.txt +10 -0
- hekatan-0.1.0/src/hekatan.egg-info/dependency_links.txt +1 -0
- hekatan-0.1.0/src/hekatan.egg-info/top_level.txt +1 -0
- hekatan-0.1.0/tests/test_display.py +46 -0
hekatan-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Giorgio Burbanelli
|
|
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.
|
hekatan-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hekatan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python display library for engineering calculations - matrices, equations, formatted output
|
|
5
|
+
Author-email: Giorgio Burbanelli <giorgioburbanelli89@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/GiorgioBurbanelli89/pyhekatan
|
|
8
|
+
Project-URL: Repository, https://github.com/GiorgioBurbanelli89/pyhekatan
|
|
9
|
+
Project-URL: Issues, https://github.com/GiorgioBurbanelli89/pyhekatan/issues
|
|
10
|
+
Keywords: engineering,calculations,matrix,equations,display,hekatan
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# hekatan
|
|
30
|
+
|
|
31
|
+
> Python display library for engineering calculations — matrices, equations, formatted output
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/hekatan/)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install hekatan
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from hekatan import matrix, eq, var, fraction, title, text, show
|
|
46
|
+
|
|
47
|
+
title("Beam Design")
|
|
48
|
+
text("Rectangular section properties:")
|
|
49
|
+
|
|
50
|
+
var("b", 300, "mm", "beam width")
|
|
51
|
+
var("h", 500, "mm", "beam height")
|
|
52
|
+
|
|
53
|
+
eq("A", 300 * 500, "mm²")
|
|
54
|
+
|
|
55
|
+
title("Stiffness Matrix", level=2)
|
|
56
|
+
K = [[12, 6, -12, 6],
|
|
57
|
+
[6, 4, -6, 2],
|
|
58
|
+
[-12, -6, 12, -6],
|
|
59
|
+
[6, 2, -6, 4]]
|
|
60
|
+
matrix(K, "K")
|
|
61
|
+
|
|
62
|
+
title("Design Ratio", level=2)
|
|
63
|
+
fraction("M_u", "φ · b · d²", "R_n")
|
|
64
|
+
|
|
65
|
+
show() # Opens formatted HTML in your browser
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## How It Works
|
|
69
|
+
|
|
70
|
+
Each function (`matrix()`, `eq()`, `var()`, etc.) works in **3 modes**:
|
|
71
|
+
|
|
72
|
+
| Mode | When | Behavior |
|
|
73
|
+
|------|------|----------|
|
|
74
|
+
| **Hekatan** | Inside Hekatan Calc (WPF/CLI) | Emits `@@HEKATAN` markers → rendered as formatted HTML |
|
|
75
|
+
| **Standalone** | Regular Python script | `show()` generates HTML, opens in browser |
|
|
76
|
+
| **Console** | Fallback | ASCII formatted output |
|
|
77
|
+
|
|
78
|
+
Mode is auto-detected via `HEKATAN_RENDER=1` environment variable.
|
|
79
|
+
|
|
80
|
+
## Functions
|
|
81
|
+
|
|
82
|
+
| Function | Description | Example |
|
|
83
|
+
|----------|-------------|---------|
|
|
84
|
+
| `matrix(data, name)` | Display formatted matrix | `matrix([[1,2],[3,4]], "A")` |
|
|
85
|
+
| `eq(name, value, unit)` | Equation: name = value unit | `eq("F", 25.5, "kN")` |
|
|
86
|
+
| `var(name, value, unit, desc)` | Variable with description | `var("b", 300, "mm", "width")` |
|
|
87
|
+
| `fraction(num, den, name)` | Formatted fraction | `fraction("M", "S", "σ")` |
|
|
88
|
+
| `title(text, level)` | Heading (h1-h6) | `title("Results", 2)` |
|
|
89
|
+
| `text(content)` | Paragraph text | `text("Design is OK.")` |
|
|
90
|
+
| `show(filename)` | Generate HTML + open browser | `show()` or `show("out.html")` |
|
|
91
|
+
| `clear()` | Clear accumulated buffer | `clear()` |
|
|
92
|
+
| `set_mode(mode)` | Force mode | `set_mode("console")` |
|
|
93
|
+
|
|
94
|
+
## Integration with Hekatan Calc
|
|
95
|
+
|
|
96
|
+
When used inside a Hekatan Calc `.hcalc` document:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
# My Calculation
|
|
100
|
+
|
|
101
|
+
@{python}
|
|
102
|
+
from hekatan import matrix, eq
|
|
103
|
+
|
|
104
|
+
K = [[12, 6], [6, 4]]
|
|
105
|
+
matrix(K, "K")
|
|
106
|
+
eq("det_K", 12*4 - 6*6)
|
|
107
|
+
@{end python}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The output is automatically formatted with Hekatan's CSS (matrices with brackets, equations with proper typography).
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT — Giorgio Burbanelli
|
hekatan-0.1.0/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# hekatan
|
|
2
|
+
|
|
3
|
+
> Python display library for engineering calculations — matrices, equations, formatted output
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/hekatan/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install hekatan
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from hekatan import matrix, eq, var, fraction, title, text, show
|
|
18
|
+
|
|
19
|
+
title("Beam Design")
|
|
20
|
+
text("Rectangular section properties:")
|
|
21
|
+
|
|
22
|
+
var("b", 300, "mm", "beam width")
|
|
23
|
+
var("h", 500, "mm", "beam height")
|
|
24
|
+
|
|
25
|
+
eq("A", 300 * 500, "mm²")
|
|
26
|
+
|
|
27
|
+
title("Stiffness Matrix", level=2)
|
|
28
|
+
K = [[12, 6, -12, 6],
|
|
29
|
+
[6, 4, -6, 2],
|
|
30
|
+
[-12, -6, 12, -6],
|
|
31
|
+
[6, 2, -6, 4]]
|
|
32
|
+
matrix(K, "K")
|
|
33
|
+
|
|
34
|
+
title("Design Ratio", level=2)
|
|
35
|
+
fraction("M_u", "φ · b · d²", "R_n")
|
|
36
|
+
|
|
37
|
+
show() # Opens formatted HTML in your browser
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How It Works
|
|
41
|
+
|
|
42
|
+
Each function (`matrix()`, `eq()`, `var()`, etc.) works in **3 modes**:
|
|
43
|
+
|
|
44
|
+
| Mode | When | Behavior |
|
|
45
|
+
|------|------|----------|
|
|
46
|
+
| **Hekatan** | Inside Hekatan Calc (WPF/CLI) | Emits `@@HEKATAN` markers → rendered as formatted HTML |
|
|
47
|
+
| **Standalone** | Regular Python script | `show()` generates HTML, opens in browser |
|
|
48
|
+
| **Console** | Fallback | ASCII formatted output |
|
|
49
|
+
|
|
50
|
+
Mode is auto-detected via `HEKATAN_RENDER=1` environment variable.
|
|
51
|
+
|
|
52
|
+
## Functions
|
|
53
|
+
|
|
54
|
+
| Function | Description | Example |
|
|
55
|
+
|----------|-------------|---------|
|
|
56
|
+
| `matrix(data, name)` | Display formatted matrix | `matrix([[1,2],[3,4]], "A")` |
|
|
57
|
+
| `eq(name, value, unit)` | Equation: name = value unit | `eq("F", 25.5, "kN")` |
|
|
58
|
+
| `var(name, value, unit, desc)` | Variable with description | `var("b", 300, "mm", "width")` |
|
|
59
|
+
| `fraction(num, den, name)` | Formatted fraction | `fraction("M", "S", "σ")` |
|
|
60
|
+
| `title(text, level)` | Heading (h1-h6) | `title("Results", 2)` |
|
|
61
|
+
| `text(content)` | Paragraph text | `text("Design is OK.")` |
|
|
62
|
+
| `show(filename)` | Generate HTML + open browser | `show()` or `show("out.html")` |
|
|
63
|
+
| `clear()` | Clear accumulated buffer | `clear()` |
|
|
64
|
+
| `set_mode(mode)` | Force mode | `set_mode("console")` |
|
|
65
|
+
|
|
66
|
+
## Integration with Hekatan Calc
|
|
67
|
+
|
|
68
|
+
When used inside a Hekatan Calc `.hcalc` document:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
# My Calculation
|
|
72
|
+
|
|
73
|
+
@{python}
|
|
74
|
+
from hekatan import matrix, eq
|
|
75
|
+
|
|
76
|
+
K = [[12, 6], [6, 4]]
|
|
77
|
+
matrix(K, "K")
|
|
78
|
+
eq("det_K", 12*4 - 6*6)
|
|
79
|
+
@{end python}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The output is automatically formatted with Hekatan's CSS (matrices with brackets, equations with proper typography).
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT — Giorgio Burbanelli
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hekatan"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python display library for engineering calculations - matrices, equations, formatted output"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Giorgio Burbanelli", email = "giorgioburbanelli89@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["engineering", "calculations", "matrix", "equations", "display", "hekatan"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Intended Audience :: Education",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.8",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Topic :: Scientific/Engineering",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/GiorgioBurbanelli89/pyhekatan"
|
|
34
|
+
Repository = "https://github.com/GiorgioBurbanelli89/pyhekatan"
|
|
35
|
+
Issues = "https://github.com/GiorgioBurbanelli89/pyhekatan/issues"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
where = ["src"]
|
hekatan-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hekatan - Python display library for engineering calculations.
|
|
3
|
+
|
|
4
|
+
Works in 3 modes:
|
|
5
|
+
1. Inside Hekatan Calc (WPF/CLI) - emits markers for formatted HTML rendering
|
|
6
|
+
2. Standalone Python - show() generates HTML and opens in browser
|
|
7
|
+
3. Console fallback - ASCII formatted output
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from hekatan import matrix, eq, var, fraction, title, text, show
|
|
11
|
+
|
|
12
|
+
A = [[1, 2], [3, 4]]
|
|
13
|
+
matrix(A, "A")
|
|
14
|
+
eq("F", 25.5, "kN")
|
|
15
|
+
var("b", 300, "mm")
|
|
16
|
+
show() # Opens HTML in browser (standalone mode)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__version__ = "0.1.0"
|
|
20
|
+
|
|
21
|
+
from hekatan.display import (
|
|
22
|
+
matrix,
|
|
23
|
+
eq,
|
|
24
|
+
var,
|
|
25
|
+
fraction,
|
|
26
|
+
title,
|
|
27
|
+
text,
|
|
28
|
+
heading,
|
|
29
|
+
show,
|
|
30
|
+
clear,
|
|
31
|
+
set_mode,
|
|
32
|
+
)
|
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core display functions for Hekatan.
|
|
3
|
+
|
|
4
|
+
Each function works in 3 modes:
|
|
5
|
+
- HEKATAN mode: prints @@HEKATAN markers (detected by C# side)
|
|
6
|
+
- STANDALONE mode: accumulates HTML, show() opens in browser
|
|
7
|
+
- CONSOLE mode: ASCII formatted output
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import tempfile
|
|
13
|
+
import webbrowser
|
|
14
|
+
from typing import Any, List, Optional, Union
|
|
15
|
+
|
|
16
|
+
# ============================================================
|
|
17
|
+
# Mode detection
|
|
18
|
+
# ============================================================
|
|
19
|
+
|
|
20
|
+
_MODE = None # 'hekatan', 'standalone', 'console'
|
|
21
|
+
_BUFFER = [] # Accumulated elements for standalone mode
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _detect_mode() -> str:
|
|
25
|
+
"""Auto-detect rendering mode."""
|
|
26
|
+
if os.environ.get("HEKATAN_RENDER") == "1":
|
|
27
|
+
return "hekatan"
|
|
28
|
+
return "standalone"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _get_mode() -> str:
|
|
32
|
+
global _MODE
|
|
33
|
+
if _MODE is None:
|
|
34
|
+
_MODE = _detect_mode()
|
|
35
|
+
return _MODE
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def set_mode(mode: str):
|
|
39
|
+
"""Force a specific mode: 'hekatan', 'standalone', or 'console'."""
|
|
40
|
+
global _MODE
|
|
41
|
+
if mode not in ("hekatan", "standalone", "console"):
|
|
42
|
+
raise ValueError(f"Invalid mode: {mode}. Use 'hekatan', 'standalone', or 'console'.")
|
|
43
|
+
_MODE = mode
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def clear():
|
|
47
|
+
"""Clear the accumulated buffer."""
|
|
48
|
+
_BUFFER.clear()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ============================================================
|
|
52
|
+
# Matrix display
|
|
53
|
+
# ============================================================
|
|
54
|
+
|
|
55
|
+
def matrix(data: List[List[Any]], name: Optional[str] = None):
|
|
56
|
+
"""
|
|
57
|
+
Display a matrix with formatted brackets.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
data: 2D list [[row1], [row2], ...]
|
|
61
|
+
name: Optional name (e.g. "A", "K")
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
matrix([[1, 2], [3, 4]], "A")
|
|
65
|
+
"""
|
|
66
|
+
mode = _get_mode()
|
|
67
|
+
|
|
68
|
+
if mode == "hekatan":
|
|
69
|
+
rows = ";".join(",".join(str(x) for x in row) for row in data)
|
|
70
|
+
marker = f"@@HEKATAN:MATRIX:{name or ''}[{rows}]"
|
|
71
|
+
print(marker)
|
|
72
|
+
|
|
73
|
+
elif mode == "standalone":
|
|
74
|
+
html = _matrix_to_html(data, name)
|
|
75
|
+
_BUFFER.append(html)
|
|
76
|
+
|
|
77
|
+
else: # console
|
|
78
|
+
_matrix_to_console(data, name)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _matrix_to_html(data: List[List[Any]], name: Optional[str] = None) -> str:
|
|
82
|
+
"""Generate HTML for a matrix using Hekatan CSS classes."""
|
|
83
|
+
rows_html = []
|
|
84
|
+
for row in data:
|
|
85
|
+
cells = "".join(f'<td class="td">{x}</td>' for x in row)
|
|
86
|
+
# Empty first/last cells create bracket effect
|
|
87
|
+
rows_html.append(f'<tr class="tr"><td class="td"></td>{cells}<td class="td"></td></tr>')
|
|
88
|
+
|
|
89
|
+
table = f'<table class="matrix">{"".join(rows_html)}</table>'
|
|
90
|
+
|
|
91
|
+
if name:
|
|
92
|
+
return f'<div class="eq"><var>{name}</var> = {table}</div>'
|
|
93
|
+
return f'<div class="eq">{table}</div>'
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _matrix_to_console(data: List[List[Any]], name: Optional[str] = None):
|
|
97
|
+
"""Print matrix in ASCII format."""
|
|
98
|
+
if not data:
|
|
99
|
+
print("[]")
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
# Calculate column widths
|
|
103
|
+
col_widths = []
|
|
104
|
+
for j in range(len(data[0])):
|
|
105
|
+
w = max(len(str(data[i][j])) for i in range(len(data)))
|
|
106
|
+
col_widths.append(w)
|
|
107
|
+
|
|
108
|
+
prefix = f"{name} = " if name else ""
|
|
109
|
+
pad = " " * len(prefix)
|
|
110
|
+
|
|
111
|
+
for i, row in enumerate(data):
|
|
112
|
+
cells = " ".join(str(row[j]).rjust(col_widths[j]) for j in range(len(row)))
|
|
113
|
+
line_prefix = prefix if i == len(data) // 2 else pad
|
|
114
|
+
print(f"{line_prefix}| {cells} |")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# ============================================================
|
|
118
|
+
# Equation display
|
|
119
|
+
# ============================================================
|
|
120
|
+
|
|
121
|
+
def eq(name: str, value: Any, unit: str = ""):
|
|
122
|
+
"""
|
|
123
|
+
Display a formatted equation: name = value [unit]
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
name: Variable name (e.g. "F", "M_u")
|
|
127
|
+
value: Numeric value
|
|
128
|
+
unit: Optional unit string (e.g. "kN", "mm")
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
eq("F", 25.5, "kN")
|
|
132
|
+
eq("A_s", 1256.64, "mm²")
|
|
133
|
+
"""
|
|
134
|
+
mode = _get_mode()
|
|
135
|
+
|
|
136
|
+
if mode == "hekatan":
|
|
137
|
+
marker = f"@@HEKATAN:EQ:{name}={value}"
|
|
138
|
+
if unit:
|
|
139
|
+
marker += f"|{unit}"
|
|
140
|
+
print(marker)
|
|
141
|
+
|
|
142
|
+
elif mode == "standalone":
|
|
143
|
+
unit_html = f' <span class="unit">{unit}</span>' if unit else ""
|
|
144
|
+
# Handle subscripts: A_s -> A<sub>s</sub>
|
|
145
|
+
display_name = _format_subscript(name)
|
|
146
|
+
html = f'<div class="eq"><var>{display_name}</var> = <b>{value}</b>{unit_html}</div>'
|
|
147
|
+
_BUFFER.append(html)
|
|
148
|
+
|
|
149
|
+
else: # console
|
|
150
|
+
unit_str = f" {unit}" if unit else ""
|
|
151
|
+
print(f"{name} = {value}{unit_str}")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# ============================================================
|
|
155
|
+
# Variable display (with description)
|
|
156
|
+
# ============================================================
|
|
157
|
+
|
|
158
|
+
def var(name: str, value: Any, unit: str = "", desc: str = ""):
|
|
159
|
+
"""
|
|
160
|
+
Display a variable with optional description.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
name: Variable name
|
|
164
|
+
value: Value
|
|
165
|
+
unit: Optional unit
|
|
166
|
+
desc: Optional description
|
|
167
|
+
|
|
168
|
+
Example:
|
|
169
|
+
var("b", 300, "mm", "ancho de la viga")
|
|
170
|
+
"""
|
|
171
|
+
mode = _get_mode()
|
|
172
|
+
|
|
173
|
+
if mode == "hekatan":
|
|
174
|
+
parts = [f"@@HEKATAN:VAR:{name}={value}"]
|
|
175
|
+
if unit:
|
|
176
|
+
parts[0] += f"|{unit}"
|
|
177
|
+
if desc:
|
|
178
|
+
parts[0] += f"|{desc}"
|
|
179
|
+
print(parts[0])
|
|
180
|
+
|
|
181
|
+
elif mode == "standalone":
|
|
182
|
+
display_name = _format_subscript(name)
|
|
183
|
+
unit_html = f' <span class="unit">{unit}</span>' if unit else ""
|
|
184
|
+
desc_html = f' <span class="desc">— {desc}</span>' if desc else ""
|
|
185
|
+
html = f'<div class="eq"><var>{display_name}</var> = <b>{value}</b>{unit_html}{desc_html}</div>'
|
|
186
|
+
_BUFFER.append(html)
|
|
187
|
+
|
|
188
|
+
else: # console
|
|
189
|
+
unit_str = f" {unit}" if unit else ""
|
|
190
|
+
desc_str = f" - {desc}" if desc else ""
|
|
191
|
+
print(f"{name} = {value}{unit_str}{desc_str}")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ============================================================
|
|
195
|
+
# Fraction display
|
|
196
|
+
# ============================================================
|
|
197
|
+
|
|
198
|
+
def fraction(numerator: Any, denominator: Any, name: Optional[str] = None):
|
|
199
|
+
"""
|
|
200
|
+
Display a fraction.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
numerator: Top value
|
|
204
|
+
denominator: Bottom value
|
|
205
|
+
name: Optional name for the result
|
|
206
|
+
|
|
207
|
+
Example:
|
|
208
|
+
fraction("M_u", "phi * b * d²", "R_n")
|
|
209
|
+
"""
|
|
210
|
+
mode = _get_mode()
|
|
211
|
+
|
|
212
|
+
if mode == "hekatan":
|
|
213
|
+
marker = f"@@HEKATAN:FRAC:{name or ''}={numerator}/{denominator}"
|
|
214
|
+
print(marker)
|
|
215
|
+
|
|
216
|
+
elif mode == "standalone":
|
|
217
|
+
name_html = f'<var>{_format_subscript(name)}</var> = ' if name else ""
|
|
218
|
+
html = (
|
|
219
|
+
f'<div class="eq">{name_html}'
|
|
220
|
+
f'<span class="dvc">'
|
|
221
|
+
f'<span class="dvl">{numerator}</span>'
|
|
222
|
+
f'<span class="dvl">{denominator}</span>'
|
|
223
|
+
f'</span></div>'
|
|
224
|
+
)
|
|
225
|
+
_BUFFER.append(html)
|
|
226
|
+
|
|
227
|
+
else: # console
|
|
228
|
+
prefix = f"{name} = " if name else ""
|
|
229
|
+
num_str = str(numerator)
|
|
230
|
+
den_str = str(denominator)
|
|
231
|
+
width = max(len(num_str), len(den_str))
|
|
232
|
+
print(f"{prefix}{num_str.center(width)}")
|
|
233
|
+
print(f"{' ' * len(prefix)}{'-' * width}")
|
|
234
|
+
print(f"{' ' * len(prefix)}{den_str.center(width)}")
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# ============================================================
|
|
238
|
+
# Text elements
|
|
239
|
+
# ============================================================
|
|
240
|
+
|
|
241
|
+
def title(text_content: str, level: int = 1):
|
|
242
|
+
"""Display a heading."""
|
|
243
|
+
mode = _get_mode()
|
|
244
|
+
tag = f"h{min(level, 6)}"
|
|
245
|
+
|
|
246
|
+
if mode == "hekatan":
|
|
247
|
+
print(f"@@HEKATAN:TITLE:{level}|{text_content}")
|
|
248
|
+
|
|
249
|
+
elif mode == "standalone":
|
|
250
|
+
_BUFFER.append(f"<{tag}>{text_content}</{tag}>")
|
|
251
|
+
|
|
252
|
+
else:
|
|
253
|
+
marker = "#" * level
|
|
254
|
+
print(f"\n{marker} {text_content}\n")
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def heading(text_content: str, level: int = 2):
|
|
258
|
+
"""Alias for title()."""
|
|
259
|
+
title(text_content, level)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def text(content: str):
|
|
263
|
+
"""Display plain text or markdown."""
|
|
264
|
+
mode = _get_mode()
|
|
265
|
+
|
|
266
|
+
if mode == "hekatan":
|
|
267
|
+
print(f"@@HEKATAN:TEXT:{content}")
|
|
268
|
+
|
|
269
|
+
elif mode == "standalone":
|
|
270
|
+
_BUFFER.append(f"<p>{content}</p>")
|
|
271
|
+
|
|
272
|
+
else:
|
|
273
|
+
print(content)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# ============================================================
|
|
277
|
+
# Show (standalone mode - generates HTML)
|
|
278
|
+
# ============================================================
|
|
279
|
+
|
|
280
|
+
def show(filename: Optional[str] = None):
|
|
281
|
+
"""
|
|
282
|
+
Generate HTML document and open in browser.
|
|
283
|
+
Only works in standalone mode.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
filename: Optional output file path. If None, uses temp file.
|
|
287
|
+
"""
|
|
288
|
+
if not _BUFFER:
|
|
289
|
+
print("hekatan: nothing to show")
|
|
290
|
+
return
|
|
291
|
+
|
|
292
|
+
html = _generate_html()
|
|
293
|
+
|
|
294
|
+
if filename:
|
|
295
|
+
path = filename
|
|
296
|
+
else:
|
|
297
|
+
fd, path = tempfile.mkstemp(suffix=".html", prefix="hekatan_")
|
|
298
|
+
os.close(fd)
|
|
299
|
+
|
|
300
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
301
|
+
f.write(html)
|
|
302
|
+
|
|
303
|
+
webbrowser.open(f"file://{os.path.abspath(path)}")
|
|
304
|
+
print(f"hekatan: opened {path}")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def _generate_html() -> str:
|
|
308
|
+
"""Generate complete HTML document with Hekatan CSS."""
|
|
309
|
+
body = "\n".join(_BUFFER)
|
|
310
|
+
return f"""<!DOCTYPE html>
|
|
311
|
+
<html lang="en">
|
|
312
|
+
<head>
|
|
313
|
+
<meta charset="UTF-8">
|
|
314
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
315
|
+
<title>Hekatan Output</title>
|
|
316
|
+
<style>
|
|
317
|
+
{_CSS}
|
|
318
|
+
</style>
|
|
319
|
+
</head>
|
|
320
|
+
<body>
|
|
321
|
+
<div class="hekatan-doc">
|
|
322
|
+
{body}
|
|
323
|
+
</div>
|
|
324
|
+
</body>
|
|
325
|
+
</html>"""
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# ============================================================
|
|
329
|
+
# Helpers
|
|
330
|
+
# ============================================================
|
|
331
|
+
|
|
332
|
+
def _format_subscript(name: str) -> str:
|
|
333
|
+
"""Convert A_s to A<sub>s</sub>."""
|
|
334
|
+
if "_" in name:
|
|
335
|
+
parts = name.split("_", 1)
|
|
336
|
+
return f"{parts[0]}<sub>{parts[1]}</sub>"
|
|
337
|
+
return name
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# ============================================================
|
|
341
|
+
# Embedded CSS (matches Hekatan Calc rendering)
|
|
342
|
+
# ============================================================
|
|
343
|
+
|
|
344
|
+
_CSS = """
|
|
345
|
+
/* Hekatan Display CSS */
|
|
346
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
347
|
+
|
|
348
|
+
body {
|
|
349
|
+
font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
|
|
350
|
+
font-size: 11pt;
|
|
351
|
+
line-height: 1.6;
|
|
352
|
+
color: #333;
|
|
353
|
+
background: #fff;
|
|
354
|
+
padding: 24px 32px;
|
|
355
|
+
max-width: 900px;
|
|
356
|
+
margin: 0 auto;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.hekatan-doc { padding: 16px 0; }
|
|
360
|
+
|
|
361
|
+
h1 { font-size: 1.8em; margin: 16px 0 8px; color: #1a1a1a; border-bottom: 2px solid #e0c060; padding-bottom: 4px; }
|
|
362
|
+
h2 { font-size: 1.4em; margin: 14px 0 6px; color: #2a2a2a; }
|
|
363
|
+
h3 { font-size: 1.15em; margin: 12px 0 4px; color: #333; }
|
|
364
|
+
|
|
365
|
+
p { margin: 6px 0; }
|
|
366
|
+
|
|
367
|
+
/* Equation line */
|
|
368
|
+
.eq {
|
|
369
|
+
font-family: 'Cambria Math', 'Latin Modern Math', 'STIX Two Math', serif;
|
|
370
|
+
font-size: 11pt;
|
|
371
|
+
line-height: 2;
|
|
372
|
+
margin: 2px 0;
|
|
373
|
+
display: flex;
|
|
374
|
+
align-items: center;
|
|
375
|
+
gap: 6px;
|
|
376
|
+
flex-wrap: wrap;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.eq var {
|
|
380
|
+
font-style: italic;
|
|
381
|
+
color: #333;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.eq b {
|
|
385
|
+
font-weight: 600;
|
|
386
|
+
color: #1a1a1a;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.unit {
|
|
390
|
+
font-size: 0.9em;
|
|
391
|
+
color: #666;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.desc {
|
|
395
|
+
font-size: 0.9em;
|
|
396
|
+
color: #888;
|
|
397
|
+
font-style: italic;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Matrix */
|
|
401
|
+
.matrix {
|
|
402
|
+
display: inline-table;
|
|
403
|
+
border-collapse: collapse;
|
|
404
|
+
margin: 4px 2px;
|
|
405
|
+
vertical-align: middle;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.matrix .tr {
|
|
409
|
+
display: table-row;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.matrix .td {
|
|
413
|
+
display: table-cell;
|
|
414
|
+
text-align: center;
|
|
415
|
+
padding: 2px 8px;
|
|
416
|
+
font-size: 10.5pt;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* Bracket effect: first and last cells have borders */
|
|
420
|
+
.matrix .tr .td:first-child {
|
|
421
|
+
border-left: 2px solid #333;
|
|
422
|
+
border-top: 2px solid #333;
|
|
423
|
+
border-bottom: 2px solid #333;
|
|
424
|
+
padding: 2px 4px;
|
|
425
|
+
width: 4px;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.matrix .tr:first-child .td:first-child { border-bottom: none; }
|
|
429
|
+
.matrix .tr:last-child .td:first-child { border-top: none; }
|
|
430
|
+
.matrix .tr:not(:first-child):not(:last-child) .td:first-child { border-top: none; border-bottom: none; }
|
|
431
|
+
|
|
432
|
+
.matrix .tr .td:last-child {
|
|
433
|
+
border-right: 2px solid #333;
|
|
434
|
+
border-top: 2px solid #333;
|
|
435
|
+
border-bottom: 2px solid #333;
|
|
436
|
+
padding: 2px 4px;
|
|
437
|
+
width: 4px;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.matrix .tr:first-child .td:last-child { border-bottom: none; }
|
|
441
|
+
.matrix .tr:last-child .td:last-child { border-top: none; }
|
|
442
|
+
.matrix .tr:not(:first-child):not(:last-child) .td:last-child { border-top: none; border-bottom: none; }
|
|
443
|
+
|
|
444
|
+
/* Fraction */
|
|
445
|
+
.dvc {
|
|
446
|
+
display: inline-flex;
|
|
447
|
+
flex-direction: column;
|
|
448
|
+
align-items: center;
|
|
449
|
+
vertical-align: middle;
|
|
450
|
+
margin: 0 4px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.dvc .dvl {
|
|
454
|
+
display: block;
|
|
455
|
+
text-align: center;
|
|
456
|
+
padding: 1px 6px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.dvc .dvl:first-child {
|
|
460
|
+
border-bottom: 1.5px solid #333;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* Code output */
|
|
464
|
+
.lang-output-text {
|
|
465
|
+
font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
|
|
466
|
+
font-size: 10.5pt;
|
|
467
|
+
line-height: 1.5;
|
|
468
|
+
white-space: pre-wrap;
|
|
469
|
+
color: #333;
|
|
470
|
+
padding: 4px 0;
|
|
471
|
+
margin: 4px 0;
|
|
472
|
+
}
|
|
473
|
+
"""
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hekatan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python display library for engineering calculations - matrices, equations, formatted output
|
|
5
|
+
Author-email: Giorgio Burbanelli <giorgioburbanelli89@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/GiorgioBurbanelli89/pyhekatan
|
|
8
|
+
Project-URL: Repository, https://github.com/GiorgioBurbanelli89/pyhekatan
|
|
9
|
+
Project-URL: Issues, https://github.com/GiorgioBurbanelli89/pyhekatan/issues
|
|
10
|
+
Keywords: engineering,calculations,matrix,equations,display,hekatan
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# hekatan
|
|
30
|
+
|
|
31
|
+
> Python display library for engineering calculations — matrices, equations, formatted output
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/hekatan/)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install hekatan
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from hekatan import matrix, eq, var, fraction, title, text, show
|
|
46
|
+
|
|
47
|
+
title("Beam Design")
|
|
48
|
+
text("Rectangular section properties:")
|
|
49
|
+
|
|
50
|
+
var("b", 300, "mm", "beam width")
|
|
51
|
+
var("h", 500, "mm", "beam height")
|
|
52
|
+
|
|
53
|
+
eq("A", 300 * 500, "mm²")
|
|
54
|
+
|
|
55
|
+
title("Stiffness Matrix", level=2)
|
|
56
|
+
K = [[12, 6, -12, 6],
|
|
57
|
+
[6, 4, -6, 2],
|
|
58
|
+
[-12, -6, 12, -6],
|
|
59
|
+
[6, 2, -6, 4]]
|
|
60
|
+
matrix(K, "K")
|
|
61
|
+
|
|
62
|
+
title("Design Ratio", level=2)
|
|
63
|
+
fraction("M_u", "φ · b · d²", "R_n")
|
|
64
|
+
|
|
65
|
+
show() # Opens formatted HTML in your browser
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## How It Works
|
|
69
|
+
|
|
70
|
+
Each function (`matrix()`, `eq()`, `var()`, etc.) works in **3 modes**:
|
|
71
|
+
|
|
72
|
+
| Mode | When | Behavior |
|
|
73
|
+
|------|------|----------|
|
|
74
|
+
| **Hekatan** | Inside Hekatan Calc (WPF/CLI) | Emits `@@HEKATAN` markers → rendered as formatted HTML |
|
|
75
|
+
| **Standalone** | Regular Python script | `show()` generates HTML, opens in browser |
|
|
76
|
+
| **Console** | Fallback | ASCII formatted output |
|
|
77
|
+
|
|
78
|
+
Mode is auto-detected via `HEKATAN_RENDER=1` environment variable.
|
|
79
|
+
|
|
80
|
+
## Functions
|
|
81
|
+
|
|
82
|
+
| Function | Description | Example |
|
|
83
|
+
|----------|-------------|---------|
|
|
84
|
+
| `matrix(data, name)` | Display formatted matrix | `matrix([[1,2],[3,4]], "A")` |
|
|
85
|
+
| `eq(name, value, unit)` | Equation: name = value unit | `eq("F", 25.5, "kN")` |
|
|
86
|
+
| `var(name, value, unit, desc)` | Variable with description | `var("b", 300, "mm", "width")` |
|
|
87
|
+
| `fraction(num, den, name)` | Formatted fraction | `fraction("M", "S", "σ")` |
|
|
88
|
+
| `title(text, level)` | Heading (h1-h6) | `title("Results", 2)` |
|
|
89
|
+
| `text(content)` | Paragraph text | `text("Design is OK.")` |
|
|
90
|
+
| `show(filename)` | Generate HTML + open browser | `show()` or `show("out.html")` |
|
|
91
|
+
| `clear()` | Clear accumulated buffer | `clear()` |
|
|
92
|
+
| `set_mode(mode)` | Force mode | `set_mode("console")` |
|
|
93
|
+
|
|
94
|
+
## Integration with Hekatan Calc
|
|
95
|
+
|
|
96
|
+
When used inside a Hekatan Calc `.hcalc` document:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
# My Calculation
|
|
100
|
+
|
|
101
|
+
@{python}
|
|
102
|
+
from hekatan import matrix, eq
|
|
103
|
+
|
|
104
|
+
K = [[12, 6], [6, 4]]
|
|
105
|
+
matrix(K, "K")
|
|
106
|
+
eq("det_K", 12*4 - 6*6)
|
|
107
|
+
@{end python}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The output is automatically formatted with Hekatan's CSS (matrices with brackets, equations with proper typography).
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT — Giorgio Burbanelli
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hekatan
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Basic tests for hekatan display functions."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
6
|
+
|
|
7
|
+
from hekatan import matrix, eq, var, fraction, title, text, clear, set_mode
|
|
8
|
+
import hekatan.display as disp
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_matrix_console():
|
|
12
|
+
set_mode("console")
|
|
13
|
+
matrix([[1, 2], [3, 4]], "A")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_eq_console():
|
|
17
|
+
set_mode("console")
|
|
18
|
+
eq("F", 25.5, "kN")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_var_console():
|
|
22
|
+
set_mode("console")
|
|
23
|
+
var("b", 300, "mm", "ancho")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_fraction_console():
|
|
27
|
+
set_mode("console")
|
|
28
|
+
fraction("M_u", "phi*b*d^2", "R_n")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_standalone_buffer():
|
|
32
|
+
set_mode("standalone")
|
|
33
|
+
clear()
|
|
34
|
+
matrix([[1, 2], [3, 4]], "A")
|
|
35
|
+
eq("F", 25.5, "kN")
|
|
36
|
+
var("b", 300, "mm")
|
|
37
|
+
assert len(disp._BUFFER) == 3, f"Expected 3, got {len(disp._BUFFER)}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
test_matrix_console()
|
|
42
|
+
test_eq_console()
|
|
43
|
+
test_var_console()
|
|
44
|
+
test_fraction_console()
|
|
45
|
+
test_standalone_buffer()
|
|
46
|
+
print("\nAll tests passed!")
|