floatium 0.11.0__cp313-cp313-win_amd64.whl
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.
- floatium/__init__.py +94 -0
- floatium/_autopatch.py +57 -0
- floatium/_ext.cp313-win_amd64.pyd +0 -0
- floatium/_ext.pyi +20 -0
- floatium/py.typed +0 -0
- floatium-0.11.0.dist-info/METADATA +255 -0
- floatium-0.11.0.dist-info/RECORD +10 -0
- floatium-0.11.0.dist-info/WHEEL +5 -0
- floatium-0.11.0.dist-info/licenses/LICENSE +32 -0
- floatium.pth +1 -0
floatium/__init__.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""floatium — drop-in replacement for CPython float formatting/parsing.
|
|
2
|
+
|
|
3
|
+
Backs float repr/str/__format__/__new__ with the {fmt} and fast_float C++
|
|
4
|
+
libraries to demonstrate the performance and correctness case for a
|
|
5
|
+
forthcoming CPython PEP.
|
|
6
|
+
|
|
7
|
+
Basic usage:
|
|
8
|
+
|
|
9
|
+
import floatium
|
|
10
|
+
floatium.install() # patch PyFloat_Type slots
|
|
11
|
+
repr(0.1) # -> '0.1', same as stock
|
|
12
|
+
floatium.uninstall() # restore
|
|
13
|
+
|
|
14
|
+
with floatium.patched():
|
|
15
|
+
... # patched inside the block
|
|
16
|
+
|
|
17
|
+
Autopatch on interpreter startup: set FLOATIUM_AUTOPATCH=1. See README.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from contextlib import contextmanager
|
|
23
|
+
from typing import Iterator
|
|
24
|
+
|
|
25
|
+
from floatium import _ext
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"install",
|
|
29
|
+
"uninstall",
|
|
30
|
+
"is_patched",
|
|
31
|
+
"info",
|
|
32
|
+
"patched",
|
|
33
|
+
"__version__",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
__version__ = "0.1.0.dev0"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def install(
|
|
40
|
+
format_backend: str | None = None,
|
|
41
|
+
parse_backend: str | None = None,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Install floatium's replacement slots on PyFloat_Type.
|
|
44
|
+
|
|
45
|
+
``format_backend`` and ``parse_backend`` select which compiled-in
|
|
46
|
+
implementation to use. Pass None to use the build-time defaults
|
|
47
|
+
(typically ``"fmt"`` and ``"fast_float"``). See ``info()`` for
|
|
48
|
+
which backends are available in this wheel.
|
|
49
|
+
|
|
50
|
+
Idempotent: calling install() twice is a no-op on the second call.
|
|
51
|
+
"""
|
|
52
|
+
kwargs = {}
|
|
53
|
+
if format_backend is not None:
|
|
54
|
+
kwargs["format_backend"] = format_backend
|
|
55
|
+
if parse_backend is not None:
|
|
56
|
+
kwargs["parse_backend"] = parse_backend
|
|
57
|
+
_ext.install(**kwargs)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def uninstall() -> None:
|
|
61
|
+
"""Restore the original PyFloat_Type slots."""
|
|
62
|
+
_ext.uninstall()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def is_patched() -> bool:
|
|
66
|
+
"""Return True if floatium is currently installed."""
|
|
67
|
+
return bool(_ext.is_patched())
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def info() -> dict:
|
|
71
|
+
"""Return a dict describing the current state and available backends."""
|
|
72
|
+
return _ext.info()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@contextmanager
|
|
76
|
+
def patched(
|
|
77
|
+
format_backend: str | None = None,
|
|
78
|
+
parse_backend: str | None = None,
|
|
79
|
+
) -> Iterator[None]:
|
|
80
|
+
"""Context manager that installs on entry and restores on exit.
|
|
81
|
+
|
|
82
|
+
Useful for A/B benchmarking or scoped testing::
|
|
83
|
+
|
|
84
|
+
with floatium.patched():
|
|
85
|
+
assert repr(0.1) == '0.1'
|
|
86
|
+
"""
|
|
87
|
+
was_patched = is_patched()
|
|
88
|
+
if not was_patched:
|
|
89
|
+
install(format_backend=format_backend, parse_backend=parse_backend)
|
|
90
|
+
try:
|
|
91
|
+
yield
|
|
92
|
+
finally:
|
|
93
|
+
if not was_patched:
|
|
94
|
+
uninstall()
|
floatium/_autopatch.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Autopatch hook.
|
|
2
|
+
|
|
3
|
+
This module is imported by the site-packages/floatium.pth file at
|
|
4
|
+
interpreter startup. It inspects FLOATIUM_AUTOPATCH and installs the
|
|
5
|
+
replacement slots if set.
|
|
6
|
+
|
|
7
|
+
Rationale for gating on an env var rather than patching unconditionally:
|
|
8
|
+
the .pth file mechanism affects *every* Python invocation that shares
|
|
9
|
+
this site-packages directory, including tools that should not be
|
|
10
|
+
affected (the build system, linters, etc.). Opt-in is safer for
|
|
11
|
+
a process-global mutation.
|
|
12
|
+
|
|
13
|
+
Values that trigger install:
|
|
14
|
+
FLOATIUM_AUTOPATCH=1
|
|
15
|
+
FLOATIUM_AUTOPATCH=true
|
|
16
|
+
FLOATIUM_AUTOPATCH=yes
|
|
17
|
+
|
|
18
|
+
You can also specify backends:
|
|
19
|
+
FLOATIUM_FORMAT_BACKEND=fmt
|
|
20
|
+
FLOATIUM_PARSE_BACKEND=fast_float
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import os
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _truthy(v: str | None) -> bool:
|
|
29
|
+
if v is None:
|
|
30
|
+
return False
|
|
31
|
+
return v.strip().lower() in {"1", "true", "yes", "on"}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _run() -> None:
|
|
35
|
+
if not _truthy(os.environ.get("FLOATIUM_AUTOPATCH")):
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# Import lazily so that merely having the .pth on disk doesn't drag the
|
|
39
|
+
# C extension into every Python process — only into ones that opt in.
|
|
40
|
+
try:
|
|
41
|
+
from floatium import install
|
|
42
|
+
except ImportError:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
fmt_backend = os.environ.get("FLOATIUM_FORMAT_BACKEND") or None
|
|
46
|
+
parse_backend = os.environ.get("FLOATIUM_PARSE_BACKEND") or None
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
install(format_backend=fmt_backend, parse_backend=parse_backend)
|
|
50
|
+
except Exception: # noqa: BLE001 — never break interpreter startup
|
|
51
|
+
if _truthy(os.environ.get("FLOATIUM_AUTOPATCH_DEBUG")):
|
|
52
|
+
import traceback
|
|
53
|
+
|
|
54
|
+
traceback.print_exc()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_run()
|
|
Binary file
|
floatium/_ext.pyi
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Type stubs for the compiled extension module floatium._ext."""
|
|
2
|
+
|
|
3
|
+
from typing import TypedDict
|
|
4
|
+
|
|
5
|
+
class _Info(TypedDict):
|
|
6
|
+
patched: bool
|
|
7
|
+
format_backend: str | None
|
|
8
|
+
parse_backend: str | None
|
|
9
|
+
available_format_backends: str
|
|
10
|
+
available_parse_backends: str
|
|
11
|
+
default_format_backend: str
|
|
12
|
+
default_parse_backend: str
|
|
13
|
+
|
|
14
|
+
def install(
|
|
15
|
+
format_backend: str | None = ...,
|
|
16
|
+
parse_backend: str | None = ...,
|
|
17
|
+
) -> None: ...
|
|
18
|
+
def uninstall() -> None: ...
|
|
19
|
+
def is_patched() -> bool: ...
|
|
20
|
+
def info() -> _Info: ...
|
floatium/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: floatium
|
|
3
|
+
Version: 0.11.0
|
|
4
|
+
Summary: Drop-in replacement for CPython float formatting/parsing, backed by {fmt} and fast_float. Demonstrator for a forthcoming CPython PEP.
|
|
5
|
+
Keywords: cpython,float,dtoa,fmt,fast_float,repr,format
|
|
6
|
+
Author-Email: Pieter Eendebak <pieter.eendebak@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Classifier: Programming Language :: C++
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Project-URL: Homepage, https://github.com/eendebakpt/floatium
|
|
21
|
+
Project-URL: Repository, https://github.com/eendebakpt/floatium
|
|
22
|
+
Project-URL: Issues, https://github.com/eendebakpt/floatium/issues
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Provides-Extra: test
|
|
25
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
26
|
+
Requires-Dist: hypothesis>=6; extra == "test"
|
|
27
|
+
Provides-Extra: bench
|
|
28
|
+
Requires-Dist: pyperf>=2.7; extra == "bench"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: hypothesis>=6; extra == "dev"
|
|
32
|
+
Requires-Dist: pyperf>=2.7; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# floatium
|
|
37
|
+
|
|
38
|
+
Experimental drop-in replacement for CPython's float formatting and parsing,
|
|
39
|
+
backed by the [{fmt}](https://github.com/fmtlib/fmt) and
|
|
40
|
+
[fast_float](https://github.com/fastfloat/fast_float) C++ libraries.
|
|
41
|
+
|
|
42
|
+
`pip install floatium`, set `FLOATIUM_AUTOPATCH=1`, and every subsequent
|
|
43
|
+
Python process uses `{fmt}`'s Dragonbox for `repr(float)` / `str(float)` /
|
|
44
|
+
`float.__format__` and `fast_float` for `float("...")`. Existing code,
|
|
45
|
+
existing tests, existing output — just faster. Works with an unmodified
|
|
46
|
+
stock CPython; no interpreter rebuild required.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install floatium
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### From source
|
|
55
|
+
|
|
56
|
+
Source builds require a C++17 compiler (GCC 9+, Clang 12+, or MSVC
|
|
57
|
+
2019+) and CMake ≥ 3.20.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/eendebakpt/floatium
|
|
61
|
+
cd floatium
|
|
62
|
+
pip install -e '.[test]'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Tests and benchmarks target **CPython 3.14**. No system libraries are
|
|
66
|
+
required; `{fmt}` and `fast_float` are vendored.
|
|
67
|
+
|
|
68
|
+
## Why this package exists
|
|
69
|
+
|
|
70
|
+
CPython's float formatting has gone through
|
|
71
|
+
[`Python/dtoa.c`](https://github.com/python/cpython/blob/main/Python/dtoa.c)
|
|
72
|
+
— David Gay's 1991 reference implementation — for three decades. The
|
|
73
|
+
code is ~2,800 lines of hand-tuned C and slower than modern alternatives.
|
|
74
|
+
Its parsing counterpart (`_Py_dg_strtod` in the same file) has similar
|
|
75
|
+
constraints.
|
|
76
|
+
|
|
77
|
+
Floatium demonstrates what replacing both sides looks like, as a pip
|
|
78
|
+
package against stock CPython:
|
|
79
|
+
|
|
80
|
+
- **Format** (double → string) via `{fmt}`'s Dragonbox algorithm — the
|
|
81
|
+
same algorithm that backs C++20's `std::format`. Fixed-precision
|
|
82
|
+
formatting for huge-magnitude values is routed through Ryu's
|
|
83
|
+
`d2fixed` to sidestep fmt's Dragon4 + bigint slow path.
|
|
84
|
+
- **Parse** (string → double) via `fast_float`'s Eisel–Lemire + bignum
|
|
85
|
+
path — the same algorithm Rust's `std`, Apache Arrow, and DuckDB use.
|
|
86
|
+
|
|
87
|
+
Both produce output **bit-identical** to stock CPython on every input
|
|
88
|
+
we've tested (see [DIFFERENCES.md](DIFFERENCES.md) — currently zero
|
|
89
|
+
divergences against CPython 3.15's stdlib test suite).
|
|
90
|
+
|
|
91
|
+
Library choices: `{fmt}` is MIT, header-only, and ships Dragonbox
|
|
92
|
+
+ grammar + fallbacks from a single upstream (~9.4k LOC vendored).
|
|
93
|
+
`fast_float` is Apache-2.0 / MIT / Boost-1.0 triple-licensed, header-only,
|
|
94
|
+
C++11, and used in Chromium, Apache Arrow, ClickHouse, folly, and DuckDB.
|
|
95
|
+
Ryu is Apache-2.0 / Boost-1.0 dual-licensed and only its `d2fixed` entry
|
|
96
|
+
point is vendored (~100 KB of pow10 tables). Slots are backend-swappable
|
|
97
|
+
— see [INTERNALS.md](INTERNALS.md).
|
|
98
|
+
|
|
99
|
+
## Usage
|
|
100
|
+
|
|
101
|
+
### Autopatch (recommended)
|
|
102
|
+
|
|
103
|
+
Once `floatium` is installed, setting `FLOATIUM_AUTOPATCH=1` before any
|
|
104
|
+
Python process starts installs the replacement for the life of that
|
|
105
|
+
process:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
export FLOATIUM_AUTOPATCH=1
|
|
109
|
+
python -c "import json; print(json.dumps([0.1, 0.2, 1e100]))"
|
|
110
|
+
# [0.1, 0.2, 1e+100]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The mechanism is a `.pth` file placed in `site-packages/` at install
|
|
114
|
+
time — `site.py` executes it during interpreter startup, before user
|
|
115
|
+
code, and the hook calls `install()` if the env var is set.
|
|
116
|
+
|
|
117
|
+
### Explicit
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import floatium
|
|
121
|
+
|
|
122
|
+
floatium.install() # patch PyFloat_Type slots
|
|
123
|
+
assert repr(0.1) == "0.1"
|
|
124
|
+
floatium.uninstall() # restore
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Scoped
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
import floatium
|
|
131
|
+
|
|
132
|
+
with floatium.patched():
|
|
133
|
+
do_something_float_heavy()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## What it patches
|
|
137
|
+
|
|
138
|
+
| Surface | How |
|
|
139
|
+
|-------------------------------------|-----------------------------------------------|
|
|
140
|
+
| `repr(x)`, `str(x)`, `f"{x}"` | `PyFloat_Type.tp_repr` pointer swap |
|
|
141
|
+
| `f"{x:.2f}"`, `format(x, spec)` | `__format__` entry in `PyFloat_Type.tp_dict` |
|
|
142
|
+
| `"{}".format(x)` | via `__format__` |
|
|
143
|
+
| `float("1.5")` | `PyFloat_Type.tp_new` pointer swap |
|
|
144
|
+
| `json.dumps([x])` | via `__repr__` |
|
|
145
|
+
|
|
146
|
+
`"%g" % x` is **not** patched — see [DIFFERENCES.md](DIFFERENCES.md).
|
|
147
|
+
|
|
148
|
+
## Benchmarks
|
|
149
|
+
|
|
150
|
+
Run locally with:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m bench.bench_ns_per_op --markdown # quick ns/op table
|
|
154
|
+
bench/run_all.sh # full pyperf sweep
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Numbers below are from a release CPython 3.14.3 build
|
|
158
|
+
(`python -m bench.bench_ns_per_op`, median of fastest third of samples,
|
|
159
|
+
lower is better). The default backend is `fmt_opt`; see
|
|
160
|
+
[INTERNALS.md](INTERNALS.md) for the routing. The `fmt` column is the
|
|
161
|
+
plain-fmt backend, included for A/B transparency:
|
|
162
|
+
|
|
163
|
+
| Corpus | Operation | Stock (ns) | fmt (ns) | fmt_opt (ns) | fmt vs stock | fmt_opt vs stock |
|
|
164
|
+
|-----------------|-----------------|-----------:|---------:|-------------:|-------------:|-----------------:|
|
|
165
|
+
| random_uniform | `repr(x)` | 289 | 97 | 97 | 2.99× | 2.98× |
|
|
166
|
+
| random_uniform | `f"{x:.4f}"` | 119 | 104 | 104 | 1.14× | 1.15× |
|
|
167
|
+
| random_uniform | `float(s)` | 121 | 121 | 121 | 1.00× | 1.00× |
|
|
168
|
+
| random_bits | `repr(x)` | 820 | 136 | 137 | 6.03× | 5.99× |
|
|
169
|
+
| random_bits | `f"{x:.4f}"` | 1,940 | 5,530 | 193 | 0.35× | 10.04× |
|
|
170
|
+
| random_bits | `float(s)` | 277 | 279 | 278 | 0.99× | 1.00× |
|
|
171
|
+
| financial | `repr(x)` | 173 | 80 | 80 | 2.16× | 2.15× |
|
|
172
|
+
| financial | `f"{x:.4f}"` | 146 | 99 | 101 | 1.46× | 1.44× |
|
|
173
|
+
| financial | `float(s)` | 37 | 37 | 37 | 1.00× | 1.00× |
|
|
174
|
+
| scientific | `repr(x)` | 637 | 133 | 133 | 4.79× | 4.78× |
|
|
175
|
+
| scientific | `f"{x:.4f}"` | 1,081 | 2,961 | 158 | 0.36× | 6.84× |
|
|
176
|
+
| scientific | `float(s)` | 213 | 213 | 212 | 1.00× | 1.00× |
|
|
177
|
+
| integer_valued | `repr(x)` | 143 | 88 | 88 | 1.63× | 1.64× |
|
|
178
|
+
| integer_valued | `f"{x:.4f}"` | 167 | 105 | 106 | 1.59× | 1.58× |
|
|
179
|
+
| integer_valued | `float(s)` | 43 | 43 | 43 | 1.00× | 1.00× |
|
|
180
|
+
|
|
181
|
+
**fmt_opt eliminates the fixed-mode regression.** Plain `fmt` regresses
|
|
182
|
+
by 2-3× on `random_bits` and `scientific` `f"{x:.4f}"` because
|
|
183
|
+
`fmt::detail::format_float` falls into a Dragon4 + bigint classical loop
|
|
184
|
+
when the value's decade + requested precision exceeds the 19-digit
|
|
185
|
+
Dragonbox first segment. `fmt_opt` detects that cliff from the binary
|
|
186
|
+
exponent and routes only those cases through Ryu's `d2fixed` — which is
|
|
187
|
+
block-based and always fast — while keeping fmt's fast subsegment path
|
|
188
|
+
for ordinary magnitudes. Output is bit-identical on both paths.
|
|
189
|
+
|
|
190
|
+
**Parse is flat at this layer.** `fast_float` beats `_Py_dg_strtod` on
|
|
191
|
+
raw `from_chars`, but the wrapper's per-call overhead (UTF-8 extraction,
|
|
192
|
+
whitespace strip, null-termination copy, `PyFloat_FromDouble`) cancels
|
|
193
|
+
the gain on these corpora. The speedup is recoverable either by lifting
|
|
194
|
+
the hook closer to `PyFloat_FromString` (requires an in-tree CPython
|
|
195
|
+
change, out of scope for a pip package) or by batching string-heavy
|
|
196
|
+
workloads where the per-call overhead amortizes — JSON and CSV parsers
|
|
197
|
+
are the obvious candidates.
|
|
198
|
+
|
|
199
|
+
## Running CPython's test suite against floatium
|
|
200
|
+
|
|
201
|
+
`tools/run_stdlib_tests.py` runs a curated set of CPython's own stdlib
|
|
202
|
+
regression tests with floatium autopatched. Zero divergences on the
|
|
203
|
+
default set as of the last update; see [DIFFERENCES.md](DIFFERENCES.md)
|
|
204
|
+
for the current status.
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
python tools/run_stdlib_tests.py
|
|
208
|
+
# ==> running: python -m test test_float test_strtod test_fstring ...
|
|
209
|
+
# == Tests result: SUCCESS ==
|
|
210
|
+
# All 12 tests OK.
|
|
211
|
+
# Total tests: run=1,616 skipped=210
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Limitations
|
|
215
|
+
|
|
216
|
+
See [DIFFERENCES.md](DIFFERENCES.md) for the full list. Summary:
|
|
217
|
+
|
|
218
|
+
- **`"%g" % x` is not patched.** The `%` operator calls
|
|
219
|
+
`PyOS_double_to_string` directly from `libpython`; no pip package can
|
|
220
|
+
intercept that without `LD_PRELOAD`.
|
|
221
|
+
- **Patching is process-global.** One `install()` per process; affects
|
|
222
|
+
all threads, all modules.
|
|
223
|
+
- **`Py_TPFLAGS_IMMUTABLETYPE` bypass.** We write directly to
|
|
224
|
+
`PyFloat_Type` slots, bypassing the public type-attribute API that
|
|
225
|
+
honors the flag. This is a known-stable internal technique (CPython
|
|
226
|
+
itself does it during bootstrap) but explicitly not part of the stable
|
|
227
|
+
ABI.
|
|
228
|
+
- **Free-threaded builds.** Supported; patching must happen at import
|
|
229
|
+
time (the only safe window). Method-cache invalidation uses
|
|
230
|
+
`PyType_Modified()` except on 3.15 debug builds (where that call
|
|
231
|
+
asserts on static types), in which case the wrapper falls back to
|
|
232
|
+
writing `tp_version_tag = 0` directly.
|
|
233
|
+
- **`float("1_000.5")` and `float("inf")` take the fallback path.** Both
|
|
234
|
+
parse correctly (output is bit-identical to stock) but don't benefit
|
|
235
|
+
from `fast_float`'s speed.
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
- floatium wrapper code: **MIT**.
|
|
240
|
+
- `{fmt}` (vendored in `third_party/fmt/`): **MIT**.
|
|
241
|
+
- `fast_float` (vendored in `third_party/fast_float/`): **Apache-2.0 OR
|
|
242
|
+
MIT OR Boost-1.0**.
|
|
243
|
+
- Ryu `d2fixed` (vendored in `third_party/ryu/`): **Apache-2.0 OR
|
|
244
|
+
Boost-1.0**.
|
|
245
|
+
- `src/format_short.cc` is a port of code from CPython `Python/pystrtod.c`,
|
|
246
|
+
which is under the **PSF License**. The port preserves the original
|
|
247
|
+
attribution and is compatible with downstream MIT redistribution under
|
|
248
|
+
the PSF license's permissive terms.
|
|
249
|
+
|
|
250
|
+
See `LICENSE` and the per-directory `LICENSE*` files.
|
|
251
|
+
|
|
252
|
+
## Status
|
|
253
|
+
|
|
254
|
+
Pre-alpha. v0.1.x — the API will stay small (the four functions in
|
|
255
|
+
`floatium/__init__.py`) but the internals will change.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
floatium/__init__.py,sha256=yiG0lcQ3Ts49twxoOmHEN9dqIcr7u2qsDsHdAkXV9HU,2564
|
|
2
|
+
floatium/_autopatch.py,sha256=im9IJDolZxMtkNtUl0ZtpqgVd0hT4yz6DF3FsVLem-M,1702
|
|
3
|
+
floatium/_ext.cp313-win_amd64.pyd,sha256=130diF7L-PO9MClwzS4ogz_CHr5Ifgux3vVaQwwF2Oo,171008
|
|
4
|
+
floatium/_ext.pyi,sha256=RJjP0kcsVSiuayojKaprtCTodNSVbBHbtNCB7FwwNS0,540
|
|
5
|
+
floatium/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
floatium.pth,sha256=p5A7cl0UiWSCQjKyWw-U4VoEWIC2VyBrbBcHsLSAu54,28
|
|
7
|
+
floatium-0.11.0.dist-info/METADATA,sha256=-hfiXfBe1ZYzhPmDUYC6mQOLguS4ZYqw1DX88K6Z64s,11377
|
|
8
|
+
floatium-0.11.0.dist-info/WHEEL,sha256=UZrbbE4r80xj7Ncfa6JoeTVe-77bdXLkKUA63V8pKWQ,106
|
|
9
|
+
floatium-0.11.0.dist-info/licenses/LICENSE,sha256=_v_9HBJ-rQ1tDIG-rGKZy2MBAEfk3iep9_nI6sfRtI0,1517
|
|
10
|
+
floatium-0.11.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pieter Eendebak
|
|
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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
This software vendors third-party libraries under their own licenses:
|
|
26
|
+
|
|
27
|
+
- third_party/fmt/ — MIT (see third_party/fmt/LICENSE)
|
|
28
|
+
- third_party/fast_float/ — Apache-2.0 OR MIT OR Boost-1.0
|
|
29
|
+
(see third_party/fast_float/LICENSE-*)
|
|
30
|
+
|
|
31
|
+
- src/format_short.cc is a port of code from CPython Python/pystrtod.c
|
|
32
|
+
(PSF License), redistributed in accordance with the PSF license terms.
|
floatium.pth
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import floatium._autopatch
|