calcbox 0.3.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.
- calcbox-0.3.0/LICENSE +21 -0
- calcbox-0.3.0/PKG-INFO +171 -0
- calcbox-0.3.0/README.md +134 -0
- calcbox-0.3.0/calcbox/__init__.py +16 -0
- calcbox-0.3.0/calcbox/api.py +52 -0
- calcbox-0.3.0/calcbox/backends.py +586 -0
- calcbox-0.3.0/calcbox/cli.py +45 -0
- calcbox-0.3.0/calcbox/contract.py +118 -0
- calcbox-0.3.0/calcbox/mcp_server.py +87 -0
- calcbox-0.3.0/calcbox/sandbox.py +78 -0
- calcbox-0.3.0/calcbox/worker.py +49 -0
- calcbox-0.3.0/calcbox.egg-info/PKG-INFO +171 -0
- calcbox-0.3.0/calcbox.egg-info/SOURCES.txt +20 -0
- calcbox-0.3.0/calcbox.egg-info/dependency_links.txt +1 -0
- calcbox-0.3.0/calcbox.egg-info/entry_points.txt +3 -0
- calcbox-0.3.0/calcbox.egg-info/requires.txt +28 -0
- calcbox-0.3.0/calcbox.egg-info/top_level.txt +1 -0
- calcbox-0.3.0/pyproject.toml +40 -0
- calcbox-0.3.0/setup.cfg +4 -0
- calcbox-0.3.0/tests/test_contract.py +68 -0
- calcbox-0.3.0/tests/test_numeric.py +109 -0
- calcbox-0.3.0/tests/test_symbolic.py +76 -0
calcbox-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 calcbox contributors
|
|
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.
|
calcbox-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: calcbox
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Backend-agnostic math compute kernel: symbolic, numeric, units, control — with provenance in every answer
|
|
5
|
+
Author: calcbox contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/Icefox12138/calcbox
|
|
8
|
+
Keywords: math,sympy,scipy,units,mcp,compute
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Provides-Extra: symbolic
|
|
16
|
+
Requires-Dist: sympy>=1.12; extra == "symbolic"
|
|
17
|
+
Provides-Extra: numeric
|
|
18
|
+
Requires-Dist: scipy>=1.11; extra == "numeric"
|
|
19
|
+
Requires-Dist: numpy; extra == "numeric"
|
|
20
|
+
Provides-Extra: units
|
|
21
|
+
Requires-Dist: pint>=0.23; extra == "units"
|
|
22
|
+
Provides-Extra: control
|
|
23
|
+
Requires-Dist: control>=0.9; extra == "control"
|
|
24
|
+
Requires-Dist: numpy; extra == "control"
|
|
25
|
+
Provides-Extra: api
|
|
26
|
+
Requires-Dist: fastapi>=0.110; extra == "api"
|
|
27
|
+
Requires-Dist: pydantic>=2; extra == "api"
|
|
28
|
+
Provides-Extra: mcp
|
|
29
|
+
Requires-Dist: mcp>=1.0; extra == "mcp"
|
|
30
|
+
Provides-Extra: full
|
|
31
|
+
Requires-Dist: sympy>=1.12; extra == "full"
|
|
32
|
+
Requires-Dist: scipy>=1.11; extra == "full"
|
|
33
|
+
Requires-Dist: numpy; extra == "full"
|
|
34
|
+
Requires-Dist: pint>=0.23; extra == "full"
|
|
35
|
+
Requires-Dist: control>=0.9; extra == "full"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# calcbox
|
|
39
|
+
|
|
40
|
+
Backend-agnostic math compute kernel: **symbolic, numeric, units, control** — and every
|
|
41
|
+
answer carries provenance (backend, engine version, assumptions, verification, input hash).
|
|
42
|
+
|
|
43
|
+
It knows nothing about teaching, documents or users. It is a calculator that can prove
|
|
44
|
+
what it did.
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from calcbox import compute
|
|
48
|
+
|
|
49
|
+
out = compute("x**2", "integrate")
|
|
50
|
+
# {'result': 'x**3/3', 'backend': 'sympy', 'engine_version': '1.13.1',
|
|
51
|
+
# 'verification': {'method': 'differentiate-back', 'passed': True}, ...}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Why another math tool
|
|
55
|
+
|
|
56
|
+
There are MCP servers that evaluate arithmetic and matrix operations. What they do not
|
|
57
|
+
report is **how the answer was produced**: which backend, which engine version, which
|
|
58
|
+
assumptions, and whether a second method agreed. For tutoring, for reproducible
|
|
59
|
+
research notes, and for anything a human will quote, that provenance is the point.
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"result": "x**3/3",
|
|
64
|
+
"latex": "\\frac{x^{3}}{3}",
|
|
65
|
+
"backend": "sympy",
|
|
66
|
+
"engine_version": "1.13.1",
|
|
67
|
+
"assumptions": {"variable": "x", "domain": "real"},
|
|
68
|
+
"verification": {"method": "differentiate-back", "passed": true},
|
|
69
|
+
"disputed": false,
|
|
70
|
+
"sandbox": "audit-only",
|
|
71
|
+
"input_sha256": "9f2c…",
|
|
72
|
+
"elapsed_ms": 12.4
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Install
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install calcbox # core, no backends
|
|
80
|
+
pip install "calcbox[symbolic]" # sympy (calculus, algebra, exact values)
|
|
81
|
+
pip install "calcbox[full]" # sympy + scipy + pint + control
|
|
82
|
+
pip install "calcbox[mcp]" # MCP server (stdio)
|
|
83
|
+
pip install "calcbox[api]" # FastAPI router
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Nothing is a hard dependency. A missing backend is reported as unavailable **with a
|
|
87
|
+
reason**, never as a crash.
|
|
88
|
+
|
|
89
|
+
## Use it
|
|
90
|
+
|
|
91
|
+
**Python**
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
compute("x**2", "integrate") # indefinite
|
|
95
|
+
compute("x", "integrate", target="0,1") # definite
|
|
96
|
+
compute("x**3", "diff")
|
|
97
|
+
compute("2+3*4", "value")
|
|
98
|
+
compute("x**2-1", "solve")
|
|
99
|
+
compute("sin(x)/x", "limit", point="0")
|
|
100
|
+
compute("x**2", "simplify", backend="sympy")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**CLI**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
calcbox "x**2" --op integrate
|
|
107
|
+
calcbox "sin(x)/x" --op limit --point 0 --json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**HTTP** (optional; no auth by design — that belongs to the host)
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from fastapi import FastAPI
|
|
114
|
+
from calcbox.api import create_router
|
|
115
|
+
|
|
116
|
+
app = FastAPI()
|
|
117
|
+
app.include_router(create_router())
|
|
118
|
+
# GET /v1/compute/backends
|
|
119
|
+
# POST /v1/compute {"expression": "x**2", "operation": "integrate"}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**MCP**
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"mcpServers": {
|
|
127
|
+
"calcbox": {"command": "calcbox-mcp", "args": []}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Tools: `compute`, `backends`.
|
|
133
|
+
|
|
134
|
+
## Contract
|
|
135
|
+
|
|
136
|
+
| Field | Meaning |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `operation` | `simplify`, `diff`, `integrate`, `solve`, `limit`, `value`, `latex`, `factor`, `expand`, `quad`, `minimize`, `root`, `convert`, `step`, `eval`, `check` |
|
|
139
|
+
| `backend` | `auto` infers from the operation; otherwise one of `sympy`/`scipy`/`pint`/`control`/`wolfram`/`lean` |
|
|
140
|
+
| `verification` | method + `passed`; e.g. differentiate-back for integrals, substitute-back for solutions |
|
|
141
|
+
| `disputed` | two backends disagreed (only when a cross-check runs) |
|
|
142
|
+
| `sandbox` | always `audit-only` for in-process backends |
|
|
143
|
+
|
|
144
|
+
Errors: `ComputeError` (bad request → 400) and `BackendUnavailable` (missing dependency
|
|
145
|
+
or disabled external engine → 503).
|
|
146
|
+
|
|
147
|
+
## Security
|
|
148
|
+
|
|
149
|
+
**The sandbox is audit-only.** It is a set of `sys.audit` hooks, not an OS jail. Read
|
|
150
|
+
[SECURITY.md](SECURITY.md) before exposing this to untrusted input. External engines
|
|
151
|
+
(Wolfram, Lean) are disabled unless `CALCBOX_EXTERNAL=1`.
|
|
152
|
+
|
|
153
|
+
## Status
|
|
154
|
+
|
|
155
|
+
0.3.0 — all six backends wired: SymPy, SciPy, Pint, Control, and the external
|
|
156
|
+
engines Wolfram and Lean (disabled unless CALCBOX_EXTERNAL=1; both fail with a
|
|
157
|
+
reason when the binary is absent, never silently).
|
|
158
|
+
|
|
159
|
+
15/15 parity with the implementation this was ported from, 36 tests.
|
|
160
|
+
|
|
161
|
+
Every local call runs in a killable subprocess worker (~0.2-1.2 s overhead);
|
|
162
|
+
CALCBOX_WORKER=0 runs in-process for debugging. External engines run in-process
|
|
163
|
+
because they are already separate processes.
|
|
164
|
+
|
|
165
|
+
## Releasing
|
|
166
|
+
|
|
167
|
+
See [RELEASING.md](RELEASING.md): PyPI Trusted Publishing, no tokens.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT.
|
calcbox-0.3.0/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# calcbox
|
|
2
|
+
|
|
3
|
+
Backend-agnostic math compute kernel: **symbolic, numeric, units, control** — and every
|
|
4
|
+
answer carries provenance (backend, engine version, assumptions, verification, input hash).
|
|
5
|
+
|
|
6
|
+
It knows nothing about teaching, documents or users. It is a calculator that can prove
|
|
7
|
+
what it did.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from calcbox import compute
|
|
11
|
+
|
|
12
|
+
out = compute("x**2", "integrate")
|
|
13
|
+
# {'result': 'x**3/3', 'backend': 'sympy', 'engine_version': '1.13.1',
|
|
14
|
+
# 'verification': {'method': 'differentiate-back', 'passed': True}, ...}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why another math tool
|
|
18
|
+
|
|
19
|
+
There are MCP servers that evaluate arithmetic and matrix operations. What they do not
|
|
20
|
+
report is **how the answer was produced**: which backend, which engine version, which
|
|
21
|
+
assumptions, and whether a second method agreed. For tutoring, for reproducible
|
|
22
|
+
research notes, and for anything a human will quote, that provenance is the point.
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"result": "x**3/3",
|
|
27
|
+
"latex": "\\frac{x^{3}}{3}",
|
|
28
|
+
"backend": "sympy",
|
|
29
|
+
"engine_version": "1.13.1",
|
|
30
|
+
"assumptions": {"variable": "x", "domain": "real"},
|
|
31
|
+
"verification": {"method": "differentiate-back", "passed": true},
|
|
32
|
+
"disputed": false,
|
|
33
|
+
"sandbox": "audit-only",
|
|
34
|
+
"input_sha256": "9f2c…",
|
|
35
|
+
"elapsed_ms": 12.4
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install calcbox # core, no backends
|
|
43
|
+
pip install "calcbox[symbolic]" # sympy (calculus, algebra, exact values)
|
|
44
|
+
pip install "calcbox[full]" # sympy + scipy + pint + control
|
|
45
|
+
pip install "calcbox[mcp]" # MCP server (stdio)
|
|
46
|
+
pip install "calcbox[api]" # FastAPI router
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Nothing is a hard dependency. A missing backend is reported as unavailable **with a
|
|
50
|
+
reason**, never as a crash.
|
|
51
|
+
|
|
52
|
+
## Use it
|
|
53
|
+
|
|
54
|
+
**Python**
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
compute("x**2", "integrate") # indefinite
|
|
58
|
+
compute("x", "integrate", target="0,1") # definite
|
|
59
|
+
compute("x**3", "diff")
|
|
60
|
+
compute("2+3*4", "value")
|
|
61
|
+
compute("x**2-1", "solve")
|
|
62
|
+
compute("sin(x)/x", "limit", point="0")
|
|
63
|
+
compute("x**2", "simplify", backend="sympy")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**CLI**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
calcbox "x**2" --op integrate
|
|
70
|
+
calcbox "sin(x)/x" --op limit --point 0 --json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**HTTP** (optional; no auth by design — that belongs to the host)
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from fastapi import FastAPI
|
|
77
|
+
from calcbox.api import create_router
|
|
78
|
+
|
|
79
|
+
app = FastAPI()
|
|
80
|
+
app.include_router(create_router())
|
|
81
|
+
# GET /v1/compute/backends
|
|
82
|
+
# POST /v1/compute {"expression": "x**2", "operation": "integrate"}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**MCP**
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"calcbox": {"command": "calcbox-mcp", "args": []}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Tools: `compute`, `backends`.
|
|
96
|
+
|
|
97
|
+
## Contract
|
|
98
|
+
|
|
99
|
+
| Field | Meaning |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `operation` | `simplify`, `diff`, `integrate`, `solve`, `limit`, `value`, `latex`, `factor`, `expand`, `quad`, `minimize`, `root`, `convert`, `step`, `eval`, `check` |
|
|
102
|
+
| `backend` | `auto` infers from the operation; otherwise one of `sympy`/`scipy`/`pint`/`control`/`wolfram`/`lean` |
|
|
103
|
+
| `verification` | method + `passed`; e.g. differentiate-back for integrals, substitute-back for solutions |
|
|
104
|
+
| `disputed` | two backends disagreed (only when a cross-check runs) |
|
|
105
|
+
| `sandbox` | always `audit-only` for in-process backends |
|
|
106
|
+
|
|
107
|
+
Errors: `ComputeError` (bad request → 400) and `BackendUnavailable` (missing dependency
|
|
108
|
+
or disabled external engine → 503).
|
|
109
|
+
|
|
110
|
+
## Security
|
|
111
|
+
|
|
112
|
+
**The sandbox is audit-only.** It is a set of `sys.audit` hooks, not an OS jail. Read
|
|
113
|
+
[SECURITY.md](SECURITY.md) before exposing this to untrusted input. External engines
|
|
114
|
+
(Wolfram, Lean) are disabled unless `CALCBOX_EXTERNAL=1`.
|
|
115
|
+
|
|
116
|
+
## Status
|
|
117
|
+
|
|
118
|
+
0.3.0 — all six backends wired: SymPy, SciPy, Pint, Control, and the external
|
|
119
|
+
engines Wolfram and Lean (disabled unless CALCBOX_EXTERNAL=1; both fail with a
|
|
120
|
+
reason when the binary is absent, never silently).
|
|
121
|
+
|
|
122
|
+
15/15 parity with the implementation this was ported from, 36 tests.
|
|
123
|
+
|
|
124
|
+
Every local call runs in a killable subprocess worker (~0.2-1.2 s overhead);
|
|
125
|
+
CALCBOX_WORKER=0 runs in-process for debugging. External engines run in-process
|
|
126
|
+
because they are already separate processes.
|
|
127
|
+
|
|
128
|
+
## Releasing
|
|
129
|
+
|
|
130
|
+
See [RELEASING.md](RELEASING.md): PyPI Trusted Publishing, no tokens.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""calcbox — backend-agnostic compute kernel.
|
|
2
|
+
|
|
3
|
+
from calcbox import compute, backends
|
|
4
|
+
compute("x**2", "integrate") # -> dict, see calcbox.contract
|
|
5
|
+
backend_status() # -> {"sympy": {"available": True, ...}}
|
|
6
|
+
|
|
7
|
+
Every answer carries provenance: backend, engine version, assumptions,
|
|
8
|
+
verification and an input hash. The sandbox is audit-only; see README.
|
|
9
|
+
"""
|
|
10
|
+
from .backends import backend_status, compute
|
|
11
|
+
from .contract import (BackendStatus, BackendUnavailable, ComputeError,
|
|
12
|
+
ComputeRequest, ComputeResult)
|
|
13
|
+
|
|
14
|
+
__version__ = "0.3.0"
|
|
15
|
+
__all__ = ["compute", "backend_status", "ComputeError", "BackendUnavailable",
|
|
16
|
+
"ComputeRequest", "ComputeResult", "BackendStatus", "__version__"]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Optional HTTP surface.
|
|
2
|
+
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
from calcbox.api import create_router
|
|
5
|
+
|
|
6
|
+
app = FastAPI()
|
|
7
|
+
app.include_router(create_router())
|
|
8
|
+
|
|
9
|
+
The routes mirror the contract exactly; they carry no authentication, because
|
|
10
|
+
that is the host's job (calcbox has no notion of users).
|
|
11
|
+
"""
|
|
12
|
+
from typing import Any, Dict, Optional
|
|
13
|
+
|
|
14
|
+
from . import backends as _backends
|
|
15
|
+
from .contract import BackendUnavailable, ComputeError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_router():
|
|
19
|
+
from fastapi import APIRouter, HTTPException
|
|
20
|
+
from pydantic import BaseModel
|
|
21
|
+
|
|
22
|
+
router = APIRouter()
|
|
23
|
+
|
|
24
|
+
class ComputeIn(BaseModel):
|
|
25
|
+
expression: str
|
|
26
|
+
operation: str = "simplify"
|
|
27
|
+
variable: str = "x"
|
|
28
|
+
point: str = "0"
|
|
29
|
+
target: Optional[str] = None
|
|
30
|
+
data: Optional[Dict[str, Any]] = None
|
|
31
|
+
timeout: float = 8.0
|
|
32
|
+
backend: str = "auto"
|
|
33
|
+
|
|
34
|
+
@router.get("/v1/compute/backends")
|
|
35
|
+
def get_backends():
|
|
36
|
+
return {"backends": _backends.backend_status()}
|
|
37
|
+
|
|
38
|
+
@router.post("/v1/compute")
|
|
39
|
+
def post_compute(body: ComputeIn):
|
|
40
|
+
try:
|
|
41
|
+
return _backends.compute(body.expression, operation=body.operation,
|
|
42
|
+
variable=body.variable, point=body.point,
|
|
43
|
+
target=body.target, data=body.data,
|
|
44
|
+
timeout=body.timeout, backend=body.backend)
|
|
45
|
+
except BackendUnavailable as e:
|
|
46
|
+
raise HTTPException(status_code=503, detail={"code": "backend_unavailable",
|
|
47
|
+
"detail": str(e)})
|
|
48
|
+
except ComputeError as e:
|
|
49
|
+
raise HTTPException(status_code=400, detail={"code": "bad_request",
|
|
50
|
+
"detail": str(e)})
|
|
51
|
+
|
|
52
|
+
return router
|