Minimal, fast templates for Python
Project description
Nano Templates
Minimal, fast, non-evaluating text templates for Python.
Install
Use pip, or your favorite package manager:
python -m pip install nano-template
Example
import nano_template as nt
template = nt.parse("Hello, {{ you }}!")
print(template.render({"you": "World"})) # Hello, World!
About
Nano Template is a small text templating engine, written as a Python C extension, with syntax familiar to anyone who's used Jinja/Minijinja, Django templates or Liquid.
Unlike those popular template engines, Nano Template forces you to keep application logic out of template text by implementing a reduced feature set. In this scenario, template authors and application developer are likely to be the same person (or team of people).
Syntax
[!NOTE] In Nano templates, there are no filters or tests, no relational or membership operators, and we don't have for loop helpers or
{% break %}and{% continue %}.Instead, you should process your data in Python before rendering a template, or use Minijinja.
Available tags are
{% if %},{% elif %},{% else %}and{% for %}.
Variables
<div>{{ some.variable }}</div>
<p>{{ other["variable with spaces or special characters"] }}</p>
Conditions
{% if some.variable %}
more markup
{% elif another.variable %}
alternative markup
{% else %}
default markup
{% endif %}
Loops
{% for x in y %}
more markup with {{ x }}
{% else %}
default markup (y was empty or not iterable)
{% endfor %}
Logical operators
Logical operators and, or and not use Python truthiness and precedence rules, and terms can be grouped with parentheses.
{% if not a and b %}
markup with {{ b }} and {{ c }}.
{% endif %}
Logical and and or have last value semantics.
Hello, {{ user.name or "guest" }}!
Strings
String literals and quoted variable path segments can use single or double quotes, and allow JSON-style escape sequences.
{{ greeting or "Hi \uD83D\uDE00!" }}
Output:
Hi 😀!
Whitespace control
Control whitespace before and after markup delimiters with - and ~. ~ will remove newlines but retain space and tab characters. - strips all whitespace.
<ul>
{% for x in y ~%}
<li>{{ x }}</li>
{% endfor -%}
</ul>
API
render
render(source, data) is a convenience function that parses and immediately renders a template to a string. Use this for testing or when you know you'll be rendering the template just the once.
import nano_template as nt
print(nt.render("Hello, {{ you }}!", {"you", "World"}))
render also accepts serializer and undefined keyword arguments.
parse
parse(source) parses template text and returns an instance of Template for later rendering with the render(self, data) method.
import nano_template as nt
template = nt.parse("Hello, {{ you }}!")
print(template.render({"you": "World"})) # Hello, World!
print(template.render({"you": "Sue"})) # Hello, Sue!
parse also accepts serializer and undefined keyword arguments.
Serializing objects
By default, when outputting an object with {{ and }}, lists, dictionaries and tuples are rendered in JSON format. For all other objects we render the result of str(obj).
You can change this behavior by passing a callable to parse or render as the serializer keyword argument. The callable should accept an object and return its string representation suitable for output.
This example shows how one might define a serializer that can dump data classes with json.dumps.
import json
from dataclasses import asdict
from dataclasses import dataclass
from dataclasses import is_dataclass
import nano_template as nt
@dataclass
class SomeData:
foo: str
bar: int
def json_default(obj: object) -> object:
if is_dataclass(obj) and not isinstance(obj, type):
return asdict(obj)
raise TypeError(f"Object of type {obj.__class__.__name__} is not JSON serializable")
def my_serializer(obj: object) -> str:
return (
json.dumps(obj, default=json_default)
if isinstance(obj, (list, dict, tuple))
else str(obj)
)
template = nt.parse("{{ some_object }}", serializer=my_serializer)
data = {"some_object": [SomeData("hello", 42)]}
print(template.render(data)) # [{"foo": "hello", "bar": 42}]
Undefined variables
When a template variable or property can't be resolved, an instance of the undefined type is used instead. That is, an instance of nano_template.Undefined or a subclass of it.
The default undefined type renders nothing when output, evaluates to False when tested for truthiness and is an empty iterable when looped over. You can pass an alternative undefined type as the undefined keyword argument to parse or render to change this behavior.
Here we use the built-in StrictUndefined.
import nano_template as nt
t = nt.parse("{{ foo.nosuchthing }}", undefined=nt.StrictUndefined)
print(t.render({"foo": {}}))
# nano_template._exceptions.UndefinedVariableError: 'foo.nosuchthing' is undefined
# -> '{{ foo.nosuchthing }}':1:3
# |
# 1 | {{ foo.nosuchthing }}
# | ^^^ 'foo.nosuchthing' is undefined
Or you can implement you own.
from typing import Iterator
import nano_template as nt
class MyUndefined(nt.Undefined):
def __str__(self) -> str:
return "<MISSING>"
def __bool__(self) -> bool:
return False
def __iter__(self) -> Iterator[object]:
yield from ()
t = nt.parse("{{ foo.nosuchthing }}", undefined=MyUndefined)
print(t.render({"foo": {}})) # <MISSING>
Preliminary benchmark
TODO: move this
(On an M2 Mac Mini with Python 3.13)
$ python scripts/benchmark.py
(001) 5 rounds with 10000 iterations per round.
parse c ext : best = 0.092587s | avg = 0.092743s
parse pure py : best = 2.378554s | avg = 2.385293s
just render c ext : best = 0.061812s | avg = 0.061850s
just render pure py : best = 0.314468s | avg = 0.315076s
just render jinja2 : best = 0.170373s | avg = 0.170706s
just render minijinja : best = 0.454723s | avg = 0.457256s
parse and render ext : best = 0.155797s | avg = 0.156455s
parse and render pure py : best = 2.733121s | avg = 2.745028s
parse and render jinja2 : <with caching disabled, I got bored waiting>
parse and render minijinja : best = 0.705995s | avg = 0.707589s
$ python scripts/benchmark_format.py
(002) 5 rounds with 1000000 iterations per round.
render template : best = 0.413830s | avg = 0.419547s
format string : best = 0.375050s | avg = 0.375237s
Contributing
TODO
Notes to self
TODO: move this
Python Debug Build
Build Python in debug mode from source in ~/python-debug:
./configure --prefix=$HOME/python-debug --with-pydebug
Tell uv to use the debug build instead of system or downloaded Python version:
uv sync -p <path/to/python debug binary>
Rebuild the extension in debug mode:
uv run python setup.py build_ext --inplace --force --debug
PYTHONMALLOC=debug
Use PYTHONMALLOC=debug python dev.py to activate Python's debug memory allocator, which inserts guard bytes, fills memory with known patterns, and performs validation to catch buffer overflows, use-after-free, and double frees when using Python memory APIs.
ASAN does not seem to catch these.
Manual reference leak check
(With a debug Python build.)
(A debug build will also report negative reference counts.)
If the delta is small and consistent, it's probably not a ref count leak.
import sys
from nano_template import render
before = sys.gettotalrefcount()
for i in range(10000):
render("{% if a %}a{% else %}c{% endif %}", {"a": False, "b": False})
if i % 1000 == 0:
print(f"Iteration {i}, total refcount={sys.gettotalrefcount()}")
after = sys.gettotalrefcount()
print("Refcount delta:", after - before)
Detecting leaks from reference cycles
(We shouldn't be creating any reference cycles in this project.)
import json
from nano_template import parse
import gc
# gc.set_debug(gc.DEBUG_LEAK)
# gc.set_debug(gc.DEBUG_SAVEALL)
with open("tests/fixtures/001/data.json") as fd:
data = json.load(fd)
with open("tests/fixtures/001/template.txt") as fd:
source = fd.read()
gc.disable()
gc.collect()
before = len(gc.get_objects())
parse(source).render(data)
gc.collect()
after = len(gc.get_objects())
print("Object delta:", after - before)
gc.enable()
# leaked = [o for o in gc.garbage if type(o).__module__ == "_nano_template"]
# for o in leaked:
# print(o, type(o))
ABI 3 Audit
Note that abi3audit ignores target ABI version when auditing .so files.
- Build a wheel locally with
python setup.py bdist_wheel - Run
abi3audit dist/<NAME>.whl --verbose
Example successful output:
[17:55:59] 💁 nano_template-0.1.0-cp39-abi3-linux_x86_64.whl: 1 extensions scanned; 0 ABI version mismatches and 0 ABI violations found
Release
- Manually run the Build wheels workflow.
- Clean
./dist/. - Download workflow artifacts.
- Extract artifacts to
./dist. - Build sdist with
uv run python -m build --sdist - Upload
uv run python -m twine upload dist/*
License
nano-template is distributed under the terms of the MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nano_template-0.1.1.tar.gz.
File metadata
- Download URL: nano_template-0.1.1.tar.gz
- Upload date:
- Size: 46.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc019a975f6cc68289e1469bcd8e0ffa50eca1bb49f8c8e11a5af790cb765905
|
|
| MD5 |
b934826a4c2f28e680e41513054edac1
|
|
| BLAKE2b-256 |
b9c953feb6a4c45e1847532aa2e008afa4081dbaad9afa2b4a99e2eb9461885c
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-win_arm64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-win_arm64.whl
- Upload date:
- Size: 35.5 kB
- Tags: CPython 3.14t, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11fdb9948282760175e2d778dc3ec96c8c82f28fc6ec87dfad604db3ec8e04a4
|
|
| MD5 |
e4238d1294da171d20ad7048ec470b4b
|
|
| BLAKE2b-256 |
2d0552a9c9dc2ef4371d943cc179e22793230fae98517bf4338436ffcd5bbe14
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-win_amd64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-win_amd64.whl
- Upload date:
- Size: 38.0 kB
- Tags: CPython 3.14t, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5fb2897d633b374851e8f3ee4d42628af67bb0c1a9dfc227ebbc819b7b52b869
|
|
| MD5 |
da1c8c412b7255b3f6a0a5a4025006ab
|
|
| BLAKE2b-256 |
e64e489eedf28a71a80b058d7de8471d4141023328bd7dc0462ff7b14e37da85
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-win32.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-win32.whl
- Upload date:
- Size: 35.0 kB
- Tags: CPython 3.14t, Windows x86
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65933b1327f5db2cc2f658a658abdff288d1a4106a77b8c71c164dac5da0c816
|
|
| MD5 |
b60f428551afb0bb9d853a9b071df48f
|
|
| BLAKE2b-256 |
f56dc032cf59c0265299f2bbb0613dc0fba2edf70383be294109d2086c81d5b5
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 150.5 kB
- Tags: CPython 3.14t, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7465d899bdd49a5186d6aebd48c177ad582fddb49954581ec8c3d00722befdc9
|
|
| MD5 |
462706553b0ea124be1d514ba72623c7
|
|
| BLAKE2b-256 |
c4c20e9509eedd27fe3499ebbee00c14abd89e26f8cffef8dfc6042be3278f91
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 151.9 kB
- Tags: CPython 3.14t, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c18f927f98ea48c784a85995f437cf5106b66a5486ac8e92a87ab65062d739e
|
|
| MD5 |
1a690ac4a5c4d5e3931e382bc2dd930d
|
|
| BLAKE2b-256 |
1bd1899ae2ba29945a9537d363db40af84efeb53bf61d65ceb37b3d95bfa34e7
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
- Upload date:
- Size: 153.0 kB
- Tags: CPython 3.14t, manylinux: glibc 2.17+ ARM64, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba38cbeb2194a386033895d53d9e274d5eaf2dc2a547e1e61c349729e6ad3233
|
|
| MD5 |
d22b0b55896d813bb28c7d888f04d9fa
|
|
| BLAKE2b-256 |
7b03b7adf15eb3474bacc70e914bae07340245df2575e32221689ca5554da325
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 149.9 kB
- Tags: CPython 3.14t, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55f855bda34ad8f23f2408f7d3c03a9c4b6366498e625f8a7d1cbf53e0691ca9
|
|
| MD5 |
69465b2ef295188f3af38c7bd86b2679
|
|
| BLAKE2b-256 |
d2709f9d798b2e98dfc53c5121e1130bdc81e657df3b7568ea405d48d987ad70
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-macosx_11_0_arm64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-macosx_11_0_arm64.whl
- Upload date:
- Size: 35.9 kB
- Tags: CPython 3.14t, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7b1f380c48c031ef05c8d09636f408ec3a50b036d8a4b3c8fbe3d3b39be6154
|
|
| MD5 |
c5410fbdab9072375508d7007c4a7ae2
|
|
| BLAKE2b-256 |
59a429ad3fac4709531716e3d2b4cc6a20e07bc01bc8b129701d08796eb70c25
|
File details
Details for the file nano_template-0.1.1-cp314-cp314t-macosx_10_15_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp314-cp314t-macosx_10_15_x86_64.whl
- Upload date:
- Size: 35.8 kB
- Tags: CPython 3.14t, macOS 10.15+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc0ebee681324244b467bc4837639f03f2f27fd2e425ba2adb5ca213cea8fe7f
|
|
| MD5 |
ef1edbb5560c1d2e7074f9a189f1aaeb
|
|
| BLAKE2b-256 |
a34c6c5d2259cb4fa4c3244018ce9065f2ba641b0ffe28a81c85c609b10c3801
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-win_arm64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-win_arm64.whl
- Upload date:
- Size: 33.9 kB
- Tags: CPython 3.9+, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b143c78fb5c35bafb346fcdd3eaaf5740ddf21a41971b93dd2deaaf68f650d97
|
|
| MD5 |
d56674d328eed087a6e3bb45d79d5924
|
|
| BLAKE2b-256 |
f53e3e6cd71071c842627e5318d8050615b0e79e27d4b38861252656b7aa8088
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 35.5 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8bc905e11d9c8cb9343b4ce5db20562d0b0b631346b3a62aaf910788cd6014fd
|
|
| MD5 |
61b62773b5ac40293af91d929b3f8587
|
|
| BLAKE2b-256 |
95392018e60083653df78c6ff4f23e803219edfde290418fe9dc9995c75bb82b
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-win32.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-win32.whl
- Upload date:
- Size: 32.5 kB
- Tags: CPython 3.9+, Windows x86
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ad016097776114a2c0170f2cb30f0cf68caf2ffc1b05a06fd99cfba7dd3c864
|
|
| MD5 |
b96df4ac8f41c938624853229f65569b
|
|
| BLAKE2b-256 |
97d52e0ba4eea97d6eef55c0a7ebf2ab68159fb6c370054cd7014aac9fe8ddca
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 109.8 kB
- Tags: CPython 3.9+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ced2a53b3031c3d015580de6d66814304b491b951ff55584807a3ce35d3d8d5d
|
|
| MD5 |
86b9f9c154921fae12d5d8057c2ccfd2
|
|
| BLAKE2b-256 |
961007365eeee8571b5198c5a839a7dd76f165e0bc9c45e7fad9a43936eb5f0c
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 110.5 kB
- Tags: CPython 3.9+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
399f92a787f752b1fdfce39036cd24db22dab55daf7af2fe45ced8193553da26
|
|
| MD5 |
503e3e4cbc0d46659ce76310fe5aa301
|
|
| BLAKE2b-256 |
36685a8ed20fa6cc469f4d89110a808f07744a66538b0d3d1a94d164b181166b
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
- Upload date:
- Size: 113.3 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d41be82514d36c1b281de2922d1c650faaf175818b6288cb227ddbea9026c4b4
|
|
| MD5 |
5e5b5ee6f5541ff943244ebd4d40c521
|
|
| BLAKE2b-256 |
f66bfe4efc39ba720ee12b6d049904cf97ffe1c4ff3d53a1ec006cc88a1bb530
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 111.5 kB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0fb2b71d1d554dfe224bc1ae5ff2520caeefec0f7ea798768007d4e4001e03d
|
|
| MD5 |
87a24e247c53e1fce205693727350f8f
|
|
| BLAKE2b-256 |
0e79f224fde0a5f8b29b9ee2fd7f77e75f6d88477362a9b4769e8f4b7fc34c0a
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 34.5 kB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2bd8e2b1ee938170a5f80e0c5f1ed3c9950d446fdc8f7241d89f54c713e0a1c
|
|
| MD5 |
e899c2791e93c75b551403225b157956
|
|
| BLAKE2b-256 |
31f76827f83da6611dad436f6173b46e414efbf2af1251e48907479662d32dec
|
File details
Details for the file nano_template-0.1.1-cp39-abi3-macosx_10_9_x86_64.whl.
File metadata
- Download URL: nano_template-0.1.1-cp39-abi3-macosx_10_9_x86_64.whl
- Upload date:
- Size: 34.3 kB
- Tags: CPython 3.9+, macOS 10.9+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5cfec1fba73b13f57c664ef5d5b5d4fefe6e3698937c772691dacd8c34a80d6a
|
|
| MD5 |
8458618ac4d2e267f632afcc5c94823a
|
|
| BLAKE2b-256 |
f26e4aa47e84db0f4cf78d199e2f65db771b248630e8040659558c5e36fc99e8
|