dfukit
Firmware updates over any link. dfukit is a small update protocol with a server for the device and a client for the host, both in C, a Python package and CLI that drive the C client, and a client in JavaScript for web pages.
- One protocol for every link: UART, UDP, TCP, BLE, USB, or a link of your own. dfukit sends frames; the link only has to carry them, and may lose some.
- A pipeline, not a request per frame: the host sends what the device's window allows, the device acknowledges in bulk, and a lost frame is sent again from where it went missing (go-back-N).
- Images raw or deflated, decoded on the device as they come in (miniz's inflater, built in).
- A 32-bit board ID per image target: it selects the backend that writes the image, and a device refuses IDs it does not know before it touches anything.
- Backends for what is behind a board ID: an ESP-IDF OTA slot, MCUboot's slot and RAM come with dfukit; write your own for another slot, or carry the session to a device further down a chain (pass-through).
- Resume after a lost link, with the device's state kept for a while.
- No threads, no heap and no platform code in the core: the application feeds it frames and time, and gets frames back through a callback.
The protocol and the internals are described in DESIGN.md, and what changed in CHANGELOG.md.
How an update goes
The host sends START with the image's board ID, size and CRC-32. The device prepares, then tells
the host how much data it may send ahead of the acknowledgements: the window. The host streams
DATA up to that limit and the device acknowledges as it goes. When a frame is lost, the host goes
back and sends again from the missing point (go-back-N); it does the same after a retransmission
timeout (RTO) without progress. FINISH checks the CRC and runs the backend's own checks, and
ACTIVATE switches to the new image.
Adding it to a project
With CMake, from a copy or a submodule of this repository (dfukit_ram only if you use the RAM
backend):
add_subdirectory(dfukit)
target_link_libraries(app PRIVATE dfukit dfukit_ram)
In an ESP-IDF project the repository is a component: add it to EXTRA_COMPONENT_DIRS (or
components/) and REQUIRES it. In a Zephyr build it is a module (zephyr/module.yml): add it
to ZEPHYR_EXTRA_MODULES, or to one image's <image>_EXTRA_ZEPHYR_MODULES with sysbuild, and
turn it on with CONFIG_DFUKIT.
Building and testing
pip install pytest "nanobind>=2.5"
cmake -S . -B build && cmake --build build && ctest --test-dir build --no-tests=error
For the C libraries alone, add -DDFUKIT_PYTHON=OFF to the first cmake. That build has no tests,
so leave out ctest.
The tests run the server and the client against each other through a simulated link that drops,
duplicates and delays frames, and the Python package and CLI against a device in the test process.
They are in Python, on the C code through its bindings; tests/README.md has how to measure their
coverage.
A device: the server
The server is a struct the application owns. Frames go in with dfukit_server_feed(), answers
come out through the send callback, and dfukit_server_poll() runs its timers. One task calls
into a server at a time.
#include <string.h>
#include "dfukit_server.h"
static int send_frame(void *ctx, const dfukit_peer_t *to, const uint8_t *frame, size_t len)
{
// To the peer `to` on your link (its address, as you gave it to dfukit_server_feed())
return my_link_send(to, frame, len);
}
static dfukit_server_t server;
static dfukit_backend_t backend;
void update_init(void)
{
const dfukit_server_config_t config = {
.send = send_frame,
.name = "my-device",
.max_frame = 512, // the largest frame the link carries
};
dfukit_server_init(&server, &config);
my_backend_init(&backend, 0x0000a001); // see "Backends"
dfukit_server_register(&server, &backend);
}
// For each frame from the link, and every few milliseconds
void on_frame(const uint8_t *addr, size_t addr_len, const uint8_t *frame, size_t len)
{
dfukit_peer_t from = {.len = (uint8_t)addr_len};
if (addr_len > DFUKIT_PEER_MAX) {
return; // longer than a peer: map it to 16 bytes of your own (an index, a hash)
}
memcpy(from.bytes, addr, addr_len);
dfukit_server_feed(&server, &from, frame, len, now_ms());
}
void every_10_ms(void)
{
dfukit_server_poll(&server, now_ms());
}
A peer is an opaque address of up to 16 bytes (DFUKIT_PEER_MAX): a socket address, a BLE
connection handle, a bus address; the server drops frames from a longer one. An IPv6 address
with its port is 18 bytes: give the server something shorter that names it (a slot in a table of
your own). Two peers are the same when their bytes are. The peer that starts a session owns it;
another one gets BUSY until it ends, unless it resumes the same image (see "Security").
INFO and STATUS are answered to anyone.
To take deflated images, give the server an inflater and a dictionary as large as the window the backend announces (32 KiB takes any deflate stream):
#include "dfukit_inflate.h"
static dfukit_inflate_t inflate;
static dfukit_inflater_t inflater;
static uint8_t dict[1u << 15];
dfukit_inflate_init(&inflate, &inflater, dict, sizeof(dict));
// and in the server's config: .inflater = &inflater
on_status in the config reports the session's state and progress, on every change and every
acknowledgement: for a light or a display. A pass-through session has no progress to report.
INFO lists as many boards as fit in one frame, after a name cut to fit. The C client does not send
or parse it: a C application that wants it sends the frame itself and reads the answer (DESIGN.md,
Messages). In Python it is dfukit.info(). It can warn early, but START is the real check.
Backends
A backend puts an image in place for one board ID (dfukit_backend_t, dfukit_server.h). The server
calls it in order:
| Callback | Required | When | What it does |
|---|---|---|---|
begin |
yes | START |
gets ready for an image of start->image_size bytes (may erase) |
write |
yes | data comes in | writes the decoded image at offset, in order |
window |
yes | every acknowledgement | how many more stream bytes it can take now (0: wait) |
finish |
yes | FINISH |
its own checks of the whole image; DFUKIT_PENDING while still writing |
activate |
yes | ACTIVATE |
makes the image the one that runs (restarts, or at the next boot) |
abort |
no | the session is broken off | undoes what it can |
The server does not check for missing callbacks: a required one left NULL crashes when it is
called. src/backends/ram/dfukit_ram.c is a complete backend to start from. Setting one up looks like
this:
void my_backend_init(dfukit_backend_t *backend, uint32_t board_id)
{
memset(backend, 0, sizeof(*backend));
backend->board_id = board_id;
backend->kind = DFUKIT_KIND_IMAGE;
backend->max_size = MY_SLOT_SIZE;
backend->encodings = DFUKIT_ENCODING_BIT(DFUKIT_ENCODING_RAW); // and _DEFLATE, if it fits
backend->begin = my_begin;
backend->write = my_write;
backend->window = my_window;
backend->finish = my_finish;
backend->activate = my_activate;
backend->abort = my_abort;
backend->ctx = &my_slot;
}
The application owns the backend, and it must outlive the server.
The server has checked the image's CRC-32 before it calls finish. The CRC catches accidents, not
attackers: checking signatures is up to the backend, which hands the image to whatever checks them
on its platform.
The CRC is a small module of its own (lib/crc32). Its dfukit_crc32() is weak, so an application
replaces it by defining one (a hardware engine, say), in an object file that gets linked. MSVC
has no weak symbols: there the static library gives way to the application's definition.
The ones that come with dfukit:
| Backend | Platform | Writes |
|---|---|---|
ram |
any | a buffer; for tests and for devices that handle the image themselves |
esp-idf-ota |
ESP-IDF | the next OTA slot; optionally erased ahead of time (dfukit_esp_ota_preerase()) |
mcuboot-recovery |
Zephyr, inside MCUboot | MCUboot's slot 0, from a recovery entered at reset |
A pass-through backend (kind = DFUKIT_KIND_PASSTHROUGH) does not write anything: forward
gets the session's frames as they are, for a device further down a chain, and that device's
answers go back with dfukit_server_downstream(). The server does not read the session: it ends
with the owner's ABORT, after the idle time, or when the backend calls
dfukit_server_passthrough_end(). abort is called however it ends. A pass-through backend needs
forward; its abort is optional, and the image callbacks are not used.
A backend usually ends the session once the device behind it has activated. Hand the answer on first, because ending the session first drops it without an error:
void on_frame_from_the_device_behind(const uint8_t *frame, size_t len)
{
dfukit_server_downstream(&server, frame, len, now_ms());
if (dfukit_frame_activated(frame, len)) {
dfukit_server_passthrough_end(&server);
}
}
esp-idf-ota
Writes the next OTA slot, so the partition table needs two OTA slots. FINISH runs ESP-IDF's check
of the image, and ACTIVATE makes it the boot image and restarts.
#include "dfukit_esp_ota.h"
static dfukit_esp_ota_t ota;
// window 0: 16 KiB. window_log2 12: takes deflate, with an inflater of that size in the server's
// config; 0 takes raw only
ESP_ERROR_CHECK(dfukit_esp_ota_init(&ota, &backend, 0x0000a001, 0, 12));
dfukit_server_register(&server, &backend);
Rollback is ESP-IDF's, and off unless CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is on: without it a
bad image that boots stays. With it, the new image must call
esp_ota_mark_app_valid_cancel_rollback() once it is up, or the next reset goes back to the old
one. Until it does, updates are refused with BACKEND, and the device's log says why.
After that confirmation, dfukit_esp_ota_preerase() erases the other slot in the background, so the
next update writes without waiting for erases. Asked for while the slot holds an update's image, it
waits for the next update.
mcuboot-recovery
An update inside MCUboot itself, for devices with a single application slot. MCUboot's own serial
recovery is off; dfukit's Zephyr module uses MCUboot's action hooks to enter its recovery when
the mcuboot-button0 pin is active at reset or when there is no bootable image. It listens on
the UART chosen as dfukit,uart, receives by DMA, and takes its frames encoded with
burst-link. FINISH runs MCUboot's own
check of the image, so the host hears of an image that will not boot; MCUboot checks it again at
the next boot.
The image needs burst-link as a module next to dfukit's: both in mcuboot_EXTRA_ZEPHYR_MODULES
with sysbuild.
# MCUboot's configuration (sysbuild: sysbuild/mcuboot.conf)
CONFIG_DFUKIT=y
CONFIG_DFUKIT_MCUBOOT_RECOVERY=y
CONFIG_DFUKIT_MCUBOOT_BOARD_ID=0x0000b001
CONFIG_DMA=y
/* MCUboot's devicetree overlay */
/ {
chosen {
dfukit,uart = &lpuart1;
};
};
&lpuart1 {
current-speed = <3000000>;
dmas = <&edma0 2 9>, <&edma0 3 8>;
dma-names = "rx", "tx";
};
The receive buffers (CONFIG_DFUKIT_MCUBOOT_RX_BUFFER) must each take the window
(CONFIG_DFUKIT_MCUBOOT_WINDOW): the flash's erases stop the interrupts, and everything a host
may have in flight then lands in one buffer.
Notes for integrators
- The window is a promise the backend makes to the host, not a limit the server enforces: a host
that sends past it still gets its frames to
write. A backend that buffers takes more, or fails. - One inflater serves every backend: its dictionary must take the largest
window_log2a backend announces, else a stream compressed to that window fails at its CRC. beginruns inside theSTARTit answers: it must be done within the client's tries times its RTO (4 s by default), or open with a window of 0 and do the rest in the background.activateonly schedules the switch (a restart afterdelay_ms, from a timer or a task): the server answersACTIVATEwith what it returns, so it must return before restarting.finishmay returnDFUKIT_PENDINGwhile it still writes what it buffered; the host asks again.mcuboot-recoverywrites the flash in whole write units (flash_area_align()); the last one is padded with the erased value.
Security
The protocol has no authentication. dfukit leaves this to the link and the backend:
- Anyone who can reach the device can send
START, andbeginmay erase flash before any signature has been checked. Restrict who can reach it, or authenticate the link. - A peer that knows an image's CRC-32 and sizes can take over a session on that image by resuming it. There is no other credential.
- The CRC-32 only catches accidents. To refuse an image that is not yours, the backend or the bootloader checks a signature.
A host: the client
The C client is driven like the server: dfukit_client_feed() with the device's frames,
dfukit_client_poll() every few milliseconds, frames out through send, and the image read
through read at any offset (a resend reads again), so it need not be in RAM.
#include "dfukit_client.h"
#include "dfukit_crc32.h"
dfukit_client_t client;
const dfukit_client_config_t config = {
.send = link_send,
.read = image_read,
.max_frame = 512,
};
dfukit_start_t start = {
.board_id = 0x0000a001,
.encoding = DFUKIT_ENCODING_RAW,
.image_size = image_len,
.stream_size = image_len,
};
start.crc32 = dfukit_crc32(0, image, image_len);
dfukit_client_init(&client, &config);
// true: ACTIVATE after FINISH. 0: activate now (DFUKIT_ACTIVATE_AT_NEXT_BOOT: at the next boot).
// 0: no delay before the switch, in milliseconds
dfukit_client_begin(&client, &start, true, 0, 0, now_ms());
while (dfukit_client_state(&client) < DFUKIT_CLIENT_DONE) {
// feed what came in, then:
dfukit_client_poll(&client, now_ms());
}
// DFUKIT_CLIENT_DONE, or DFUKIT_CLIENT_FAILED and dfukit_client_status() says why
After a lost link (or a DFUKIT_TIMEOUT), dfukit_client_resume() on the new one goes on where
the device stopped, or starts over when the device has no state left.
A host: Python
pip install dfukit
pip install 'dfukit[serial]' # with the serial transport (pyserial, burst-link)
import dfukit
transport = dfukit.open_transport("udp:192.168.1.20:5000")
board = dfukit.info(transport).board(0x0000A001) # None when it does not fit INFO's frame
# Compressed for the window the device has: a larger one fails at the end, with a CRC mismatch
update = dfukit.Update(
transport, image, 0x0000A001, encoding=dfukit.DEFLATE, window_log2=board.window_log2
)
update.run(progress=lambda done, total: print(done, total))
Update.run() takes a reconnect callback that returns a new transport after a lost link; the
update then resumes on it, and gives up after 70 s without progress. Once ACTIVATE is sent it does
not reconnect, because a device that restarted would be flashed again: a lost answer raises
dfukit.ActivationNotConfirmed, and the device may well be running the new image.
The CLI:
dfukit info --via udp:192.168.1.20:5000
dfukit update --via serial:/dev/ttyUSB0@3000000 --board 0x0000B001 firmware.bin
--encoding auto (the default) deflates when the board takes it, with the board's window.
The transports that come with the package are udp (one frame per datagram) and serial
(burst-link frames). Others come as plugins: a package registers a dfukit.Transport subclass
under the entry point dfukit.transports, and the CLI finds it by its name.
class MyLinkTransport(dfukit.Transport):
max_frame = 509
def open(self, address: str) -> None: ...
def send(self, frame: bytes) -> None: ... # hand each received frame to self.received()
def close(self) -> None: ...
[project.entry-points."dfukit.transports"]
mylink = "my_link.transport:MyLinkTransport"
A transport raises dfukit.LinkError when its link is gone.
The client and server directly
For a link and a clock of your own, without a transport: the same client and server as in C, driven the same way.
The caller provides the link and the clock, in
milliseconds that fit 32 bits. Unlike the C client, begin() takes the whole image as bytes.
import time
import dfukit
def now_ms() -> int:
return int(time.monotonic() * 1000) & 0xFFFFFFFF
client = dfukit.Client(link_send, lambda offset, length: image[offset : offset + length], max_frame=512)
client.begin(0x0000A001, image, now_ms())
while client.state not in (dfukit.ClientState.DONE, dfukit.ClientState.FAILED):
for frame in frames_from_the_link():
client.feed(frame, now_ms())
client.poll(now_ms())
if client.state == dfukit.ClientState.FAILED:
raise RuntimeError(dfukit.status_name(client.status))
dfukit.Server is the device's end, with add() for a backend (RamBackend, PassthroughBackend),
feed(peer, frame, now) and poll(now); its send callback gets (peer, frame).
A deflated image goes the same way: the client streams the compressed bytes, and begin() still
takes the image, for its size and CRC. The stream is raw deflate, with a window the device announces:
compressor = zlib.compressobj(9, zlib.DEFLATED, -15)
stream = compressor.compress(image) + compressor.flush()
client = dfukit.Client(link_send, lambda offset, length: stream[offset : offset + length], max_frame=512)
client.begin(0x0000A001, image, now_ms(), stream_size=len(stream), encoding=1)
On the server, server.set_inflater(dfukit.Inflate(15)) turns deflate on.
A host: JavaScript
src/js/dfukit.js is the client for a web page, on a link the page has (a WebSocket, say). It is a
plain script without dependencies, and defines dfukit:
const update = new dfukit.Update({
send: frame => socket.send(frame), // throws when the link is gone: the resends cover it
image, // a Uint8Array
boardId: 0x0000a001,
deflated: await dfukit.deflate(image), // optional
maxFrame: 509,
onProgress: (done, total) => show(done, total),
});
socket.onmessage = event => update.received(new Uint8Array(event.data));
await update.run(); // throws dfukit.UpdateError when it fails; update.resume() on a new link
dfukit.deflate() needs CompressionStream, which every current browser has. It compresses with a
32 KiB window and can not use a smaller one, so a board that announces less takes the image raw.
Like Python's Update, it does not resume once ACTIVATE is sent, because a device that restarted
would be flashed again: a lost answer is an UpdateError, and the device may well be running the new
image.
License
Apache-2.0 (LICENSE). miniz's inflater in lib/miniz is MIT
(its LICENSE).
Metadata
Release files for dfukit 2.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dfukit-2.2.0.tar.gz | 180.6 kB | With provenance | Details for dfukit-2.2.0.tar.gz |
Built distributions (wheels)
Total release size: 4.7 MB
Release files / dfukit-2.2.0.tar.gz
| Download URL | dfukit-2.2.0.tar.gz |
|---|---|
| Size | 180.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
30ff79821666d8b6c16c616be834e927356a2d0c5d6760445864052f41b1b3c5
|
|
BLAKE2b-256 checksum How to use checksums |
79275d4eee5207c14b0e6720d961c2cde64e30bfdca4d543a21853c716baa1d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-win_amd64.whl
| Download URL | dfukit-2.2.0-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 302.7 kB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
12d9ce5953ad0a85f7fa5c37d23a2456dfa6d1a9d4d8de91c002dac0659656ee
|
|
BLAKE2b-256 checksum How to use checksums |
e0c2a55dcbda4b359f6df4ea2207567000c323f0c00256f5f7c13acce3e900d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-win32.whl
| Download URL | dfukit-2.2.0-cp312-abi3-win32.whl |
|---|---|
| Size | 296.6 kB |
| Tags | CPython 3.12 Windows x86-32 abi3 |
|
SHA-256 checksum How to use checksums |
c67313a30d14e67dd9d7267d9ed9e41680bd4019b3213cb410478c64eedb241f
|
|
BLAKE2b-256 checksum How to use checksums |
274c9b09f97747ede38d3779ed63bee906048b960385704f228ac57a7abf085f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-musllinux_1_2_x86_64.whl
| Download URL | dfukit-2.2.0-cp312-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 578.0 kB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e837719d3475a954e0b07b52845e5ab5244110b8ce9b0fdefd14ed2ef1209ebe
|
|
BLAKE2b-256 checksum How to use checksums |
33bbd666aa66377c5a33d08b0f63fac69d14ef2c715f5ea4077ff9f77e5b9ee5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | dfukit-2.2.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 120.7 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
2efd8fa44a446ac7d71ae2bf5cabda7933230fe50203ec6bfe9b18b38d0ef06c
|
|
BLAKE2b-256 checksum How to use checksums |
9481dd4c9aec2fde42489c9e898236acad4ae967b54643dafffc33abbcc6ee6d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | dfukit-2.2.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 95.9 kB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1c95690de352a3ae37447a9f78b04d53c72ce6a011f45ca481ddcd3113a13d85
|
|
BLAKE2b-256 checksum How to use checksums |
3434c28c8261609159b666da032bbbe1083ff001a4c6c66063a12cdb240b56e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp312-abi3-macosx_10_14_x86_64.whl
| Download URL | dfukit-2.2.0-cp312-abi3-macosx_10_14_x86_64.whl |
|---|---|
| Size | 100.2 kB |
| Tags | CPython 3.12 abi3 macOS 10.14+ x86-64 |
|
SHA-256 checksum How to use checksums |
bb265bdaff53c8f1e6fe0c0ea3fe9a9a00408d53b3626445c8f942b434422c1d
|
|
BLAKE2b-256 checksum How to use checksums |
4bfa61b6f9deb12c835f0963aa0e5f72a18f6ad77903afdbd5ac020316b81df5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-win_amd64.whl
| Download URL | dfukit-2.2.0-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 303.3 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
6ed77d301c92c6b4646f2bdfec4d3a282793e8083f8a086f8feeb2366abc8758
|
|
BLAKE2b-256 checksum How to use checksums |
5da0acb1402b5f450b8e297c05fddd75235b7bdc459f07f55838ffc03ef1cf7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-win32.whl
| Download URL | dfukit-2.2.0-cp311-cp311-win32.whl |
|---|---|
| Size | 297.5 kB |
| Tags | CPython 3.11 Windows x86-32 |
|
SHA-256 checksum How to use checksums |
d560fd7c47b3d3faaaf0f03af6549c6d558fbace029810da400ab2018204373a
|
|
BLAKE2b-256 checksum How to use checksums |
2bc481d4e65782ce01164203fd5fd5054ac3a4860e75911fa10f4157c9fa486d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-musllinux_1_2_x86_64.whl
| Download URL | dfukit-2.2.0-cp311-cp311-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 583.0 kB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
26fb938e3c0d4c333277ca9c49315d0c1e7bdf4097677488605522b42c9f54b1
|
|
BLAKE2b-256 checksum How to use checksums |
ee7415959e9ffce2110bac9d7760e9524ac8b6ee10f520f663525cbdeee47b45
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | dfukit-2.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 125.9 kB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
a0336a64d21e52ad68989699d92fab1c1d39490e1987648b7a54ebd590db49cc
|
|
BLAKE2b-256 checksum How to use checksums |
79c74bf2024d02c247bae19bf4cc707e9aba5327e2f387a04974da2b46623d73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | dfukit-2.2.0-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 98.0 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
81d6fdefe24439fe13e4283c9128aa9ec76a6f305f1a9b2351a8b0096edb0eb3
|
|
BLAKE2b-256 checksum How to use checksums |
df423916d6af4c96952147174a5404aa6257bb68168cc2a46ee106e6441ec218
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp311-cp311-macosx_10_14_x86_64.whl
| Download URL | dfukit-2.2.0-cp311-cp311-macosx_10_14_x86_64.whl |
|---|---|
| Size | 102.2 kB |
| Tags | CPython 3.11 macOS 10.14+ x86-64 |
|
SHA-256 checksum How to use checksums |
5ee050a4d7d9bc280ef42ba35b469cc97c97d674f7f803dcb76a1936ccb14cc6
|
|
BLAKE2b-256 checksum How to use checksums |
59381bc1b6e8f33b9b15c5c3507539a86882b99a04d267609405ed99e71bc642
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-win_amd64.whl
| Download URL | dfukit-2.2.0-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 303.0 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
bb973d9b6aab3b6b2d0a7079b11b36a76dda1113f4f3d2525c7bb9a135caca8f
|
|
BLAKE2b-256 checksum How to use checksums |
3da30049b539ecae2b6a0a642d84a3849701ec53f3b65628ff8c9955be59af88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-win32.whl
| Download URL | dfukit-2.2.0-cp310-cp310-win32.whl |
|---|---|
| Size | 297.3 kB |
| Tags | CPython 3.10 Windows x86-32 |
|
SHA-256 checksum How to use checksums |
2b873b13f7dd3ee6d25f78237d83b8ac8c4445555156b4e9bd65a35c2978e954
|
|
BLAKE2b-256 checksum How to use checksums |
c5e43ae77215b3965edc2a246395393a04632a8fd0c96c4875618409956afe33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl
| Download URL | dfukit-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 582.7 kB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
c15a67751d25449cc4f03264ca4cf099a0bcee50230a0f7b27a3ad06496c6c81
|
|
BLAKE2b-256 checksum How to use checksums |
7dd6f39cd354fa6c16de4b39480508c775e6c6a3c99506fce9a61968c87bcfcd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | dfukit-2.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 125.4 kB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
392706a2727821389415ca78f26a88e0c9ebbafa3522f1a848df7db5f7dc37fd
|
|
BLAKE2b-256 checksum How to use checksums |
c961c4c2d54afa9b46b52813d3d328dd5b4108ff0dddcb6012bd567e1fe2461d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | dfukit-2.2.0-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 97.4 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0e326b49391775ca32ba0b6629fa48eaa64ab2ad52cd53edca1e6ac578ba82da
|
|
BLAKE2b-256 checksum How to use checksums |
e73dea3287b9ec022cb4f58d9e4a50bcf4fa2af5d5dc42cbc74e3cceef826bb5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / dfukit-2.2.0-cp310-cp310-macosx_10_14_x86_64.whl
| Download URL | dfukit-2.2.0-cp310-cp310-macosx_10_14_x86_64.whl |
|---|---|
| Size | 101.5 kB |
| Tags | CPython 3.10 macOS 10.14+ x86-64 |
|
SHA-256 checksum How to use checksums |
20b9735c4c1ccaa7e222a16b82dfc93bb0730a2350964c281263d3384091eed8
|
|
BLAKE2b-256 checksum How to use checksums |
d24d632d4db1c7883709512291dd052f6997ac4829f171350ef63cc3506301e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logSecurity for dfukit 2.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 19 files in this release have been uploaded with provenance metadata.
Attestation for dfukit-2.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.