Skip to main content

Python bindings for the wingfoil Rust library

Project description

🚀 Wingfoil

PyPI - Version Documentation Status CI

Wingfoil is a blazingly fast, highly scalable stream processing framework designed for latency-critical use cases such as electronic trading and real-time AI systems. You define a graph of transformations over streams; Wingfoil drives their execution in a tightly scheduled DAG, either against live data or replayed history.

The Rust engine does the heavy lifting; this wingfoil package gives you the same graph model, operators, and production-ready I/O adapters from Python.


Table of Contents


✨ Features

  • Fast — ultra-low latency and high throughput with an efficient DAG execution engine written in Rust.
  • Simple and obvious — define your graph with fluent operators; Wingfoil manages scheduling and data propagation.
  • Backtesting out of the box — switch from real-time to historical replay by flipping a single flag.
  • Production I/O adapters — CSV, KDB+, etcd, ZeroMQ, iceoryx2, FIX 4.4 (incl. TLS), Prometheus, and OTLP — ready to plug into your graph.
  • Multi-language — Rust crate and Python package today, WASM/JS/TS planned.

📦 Installation

pip install wingfoil

Wingfoil wheels are published for Linux, macOS, and Windows on CPython 3.8+.

Optional adapters require the matching server/library (KDB+, etcd, iceoryx2, a FIX counterparty, OTLP collector, etc.) but no additional Python dependencies — the adapter clients are compiled into the wheel.


⚡ Quick Start

from wingfoil import ticker

(
    ticker(1.0)                       # tick every second
        .count()                      # 1, 2, 3, ...
        .map(lambda n: f"hello, world {n}")
        .logged(">>")                 # INFO-log each value
        .run(realtime=True, duration=3.0)
)
[INFO wingfoil] 0.000_092 >> hello, world 1
[INFO wingfoil] 1.008_038 >> hello, world 2
[INFO wingfoil] 2.012_219 >> hello, world 3

run() blocks until the stop condition is reached. Pass any of:

Argument Type Meaning
realtime bool True uses wall-clock time; False is historical replay.
start float | datetime Historical start (Unix-seconds float or UTC datetime).
duration float | timedelta Stop after this many seconds of graph time.
cycles int Stop after this many engine cycles.

🧠 Core Concepts

  • Stream — a time-stamped channel of values. Streams are produced by sources (ticker, constant, I/O adapters) and transformed with operators (.map, .filter, .distinct, ...). Every operator returns a new Stream.
  • Node — anything schedulable. A Stream is a Node that also carries a value; pure side-effect sinks (.for_each, .csv_write, .zmq_pub, ...) return a Node.
  • Graph — a bundle of roots that share one engine run. Use Graph([...]) when you have several independent stream branches that must execute together (e.g. publisher + subscriber + monitoring).
  • Active vs. passive upstreams — an active upstream triggers downstream execution on tick; a passive upstream is read but does not trigger. Most built-in operators use active inputs; .sample(trigger) is the common way to fire a stream from a different clock.

Run Modes

  • realtime=True — the engine tracks wall-clock time. Use with live inputs (sockets, brokers, iceoryx2, etc.).
  • realtime=Falsehistorical replay, driven by event timestamps. Ideal for backtests and deterministic tests. In historical mode the graph runs as fast as the CPU allows; time advances purely from source events.

🧰 Stream Operators

All methods are available on Stream instances. Examples assume from wingfoil import ticker, constant, bimap, Graph.

Source operators

Operator Description
ticker(period) Emit once every period seconds. Returns a Node.
constant(value) Emit value once on the first cycle.

Transforming values

Operator Description
.map(f) Apply f(value) to each tick.
.filter(pred) Drop values where pred(value) is false.
.distinct() Drop consecutive duplicates.
.difference() Emit current - previous.
.delay(seconds) Replay values delayed by seconds.
getattr(s, 'not')() Logical/arithmetic negation (the literal method name is not; invoke via getattr because not is a Python keyword).
.limit(n) Pass through at most n values, then stop.
.sample(trigger) Re-emit the current value on each trigger tick.

Aggregation

Operator Description
.count() Emit tick count: 1, 2, 3, ...
.sum() Running sum (values must be numeric).
.average() Running mean (values must be numeric).
.buffer(n) Tumbling window of size n.
.collect() Accumulate every value into a list emitted each cycle.
.with_time() Pair each value with graph-time as (seconds, value).
.dataframe() Collect [(time, value), ...] for pandas (see below).

Observing and sinking

Operator Description
.inspect(f) Call f(value) and pass the value through.
.logged("label") INFO-log each value and pass it through.
.for_each(f) Terminal sink: f(value, time) on every tick.
getattr(s, 'finally')(f) Terminal sink: f(final_value) called once at shutdown (literal method name finally collides with Python's keyword, so use getattr).
.peek_value() After run(), inspect the last emitted value.

Execution

Operator Description
.run(realtime, start=, duration=, cycles=) Build and run a one-root graph.
Graph([...]).run(...) Build and run a multi-root graph.

Example: most operators in one pipeline

from wingfoil import ticker

avg_of_odds = (
    ticker(0.1)
        .count()
        .filter(lambda x: x % 2 == 1)   # 1, 3, 5, ...
        .map(float)
        .average()                      # running mean
        .logged("avg")
)

avg_of_odds.run(realtime=False, cycles=10)
print("last:", avg_of_odds.peek_value())

🧱 Composing Streams: Graph, bimap, CustomStream

Graph — run several roots together

from wingfoil import ticker, Graph

quotes = ticker(0.1).count().map(lambda i: 100 + i).logged("quote")
heartbeat = ticker(1.0).count().logged("heartbeat")

Graph([quotes, heartbeat]).run(realtime=True, duration=2.5)

bimap — fuse two streams

from wingfoil import ticker, constant, bimap

a = ticker(0.1).count()                       # 1, 2, 3, ...
b = constant(0.5).sample(ticker(0.1))         # 0.5 on every tick

(bimap(a, b, lambda x, y: x + y)
    .logged("sum")
    .run(realtime=False, cycles=5))

CustomStream — write your own operator in Python

Subclass CustomStream and implement cycle():

import math
from wingfoil import ticker, CustomStream

class Polynomial(CustomStream):
    """Sum of upstream[i] * 10**i."""

    def cycle(self):
        value = sum(
            src.peek_value() * math.pow(10, i)
            for i, src in enumerate(self.upstreams())
        )
        self.set_value(value)
        return True

source = ticker(0.1).count()
(
    Polynomial([source] * 3)
        .map(lambda x: x * 0.01)
        .logged("poly")
        .run(realtime=False, cycles=5)
)

🕰️ Backtesting with Historical Mode

Pass realtime=False to drive the graph from source timestamps rather than the wall clock. Add start= if your sources require a specific epoch start (such as kdb_read), and cap the replay with duration= or cycles=.

from datetime import datetime, timezone
from wingfoil import ticker

stream = ticker(0.01).count().collect()
stream.run(
    realtime=False,
    start=datetime(2025, 1, 1, tzinfo=timezone.utc),
    cycles=5,
)
print(stream.peek_value())   # [1, 2, 3, 4, 5]

Historical mode is deterministic — it's the right mode for unit tests and strategy backtests.


🐼 Pandas Integration

wingfoil ships with two pandas helpers:

  • stream.dataframe() — collects (time, value) pairs into a list; combine with wingfoil.to_dataframe to materialise a pandas.DataFrame.
  • wingfoil.build_dataframe({"col": stream, ...}) — aligns several .dataframe() streams by graph time.
from wingfoil import ticker, Graph, build_dataframe

source = ticker(0.01).count().limit(5)
prices = source.map(lambda i: 100 + i).dataframe()
quantities = source.map(lambda _: 10).dataframe()

Graph([prices, quantities]).run(realtime=False)

df = build_dataframe({"price": prices, "qty": quantities})
print(df)
#       time  price  qty
# 0  0.0e+00    101   10
# 1  1.0e-02    102   10
# ...

A single-stream variant using to_dataframe:

from wingfoil import ticker, to_dataframe

stream = (
    ticker(0.01)
        .count()
        .limit(5)
        .map(lambda i: {"price": 100 + i, "qty": 10})
        .dataframe()
)
stream.run(realtime=False)
df = to_dataframe(stream.peek_value())
print(df)

🔌 I/O Adapters

All adapters are exposed from the top-level wingfoil module. Every write method (csv_write, kdb_write, etcd_pub, zmq_pub, iceoryx2_pub, otlp_push) returns a Node — drive it by calling .run(...).

CSV

Read a CSV file into a stream of dicts (keys = column headers, values = strings). The file must have a header row and a timestamp column encoded as integer nanoseconds since the Unix epoch.

from wingfoil import csv_read

rows = csv_read("prices.csv", time_column="time_ns").collect()
rows.run(realtime=False)
print(rows.peek_value())         # [{'time_ns': '...', 'sym': 'AAPL', ...}, ...]

Write a stream of dicts to CSV. Headers are inferred from the first dict; a time column with graph-time nanoseconds is prepended automatically.

from wingfoil import ticker

(
    ticker(0.1)
        .count()
        .limit(5)
        .map(lambda i: {"sym": "AAPL", "price": 100.0 + i})
        .csv_write("out.csv")
        .run(realtime=False)
)

KDB+

Start a q process (q -p 5000) and create the target table:

test_trades:([]time:`timestamp$();sym:`symbol$();price:`float$();qty:`long$())
from wingfoil import ticker, kdb_read

HOST, PORT, TABLE = "localhost", 5000, "test_trades"

# Write: each dict becomes one row; "columns" names the non-time columns.
(
    ticker(1.0).count().limit(10)
        .map(lambda i: {"sym": "AAPL", "price": 100.0 + i, "qty": i * 10 + 1})
        .kdb_write(
            host=HOST, port=PORT, table=TABLE,
            columns=[("sym", "symbol"), ("price", "float"), ("qty", "long")],
        )
        .run(realtime=False)
)

# Read: time-sliced query; returns a stream of dicts.
# `start` and `duration` bound the replay window against the KDB time column.
rows = kdb_read(
    host=HOST, port=PORT,
    query=f"select from {TABLE}",
    time_col="time",
    chunk_size=10_000,
).collect()
rows.run(realtime=False, start=946684800.0, duration=86400.0)
print(rows.peek_value())

Supported kdb_write column types: "symbol", "float", "long", "int", "bool".

etcd

Start etcd (docker run --rm -p 2379:2379 gcr.io/etcd-development/etcd:v3.5.0).

from wingfoil import ticker, etcd_sub

ENDPOINT = "http://localhost:2379"

# Publish: each dict = {"key": str, "value": bytes}, or a list of them per tick.
(
    ticker(1.0).count().limit(3)
        .map(lambda i: {"key": f"/wf/item/{i}", "value": str(i).encode()})
        .etcd_pub(ENDPOINT, lease_ttl=30.0, force=True)
        .run(realtime=True)
)

# Subscribe: snapshot + watch events under a prefix; each tick = list[event].
events = etcd_sub(ENDPOINT, "/wf/").inspect(print)
events.run(realtime=True, duration=2.0)

Event dicts have shape: {"kind": "put"|"delete", "key": str, "value": bytes, "revision": int}.

ZeroMQ

Cross-language compatible — the Rust publisher/subscriber inter-operate with Python on both sides.

Direct mode — hard-coded address, no discovery infrastructure:

# zmq_pub.py
import wingfoil as wf

(
    wf.ticker(0.5).count()
        .map(lambda n: str(n).encode())
        .zmq_pub(port=7779)
        .run(realtime=True)
)
# zmq_sub.py
import wingfoil as wf

data, status = wf.zmq_sub("tcp://127.0.0.1:7779")
data_node = data.inspect(lambda msgs: [print("msg:", m) for m in msgs])
status_node = status.inspect(lambda s: print("status:", s))
wf.Graph([data_node, status_node]).run(realtime=True)

zmq_sub returns (data_stream, status_stream). Each data_stream tick yields list[bytes] of messages received that cycle. status_stream yields "connected" / "disconnected".

etcd discovery — publishers register under a service name; subscribers look it up. Useful for dynamic deployments. Requires a running etcd.

# publisher
wf.ticker(0.5).count().map(lambda n: str(n).encode()) \
    .zmq_pub_etcd("quotes", 7779, "http://127.0.0.1:2379") \
    .run(realtime=True)

# subscriber
data, status = wf.zmq_sub_etcd("quotes", "http://127.0.0.1:2379")

For multi-host deployments where 127.0.0.1 isn't routable, use zmq_pub_etcd_on(name, address, port, endpoint).

iceoryx2 (shared memory)

Zero-copy pub/sub over shared memory. Requires building wingfoil with the iceoryx2 feature (opt-in; see Build from Source).

from wingfoil import ticker, iceoryx2_sub, Iceoryx2ServiceVariant, Iceoryx2Mode, Graph

service = "wingfoil/demo"

sub = iceoryx2_sub(
    service,
    variant=Iceoryx2ServiceVariant.Local,   # or Ipc
    mode=Iceoryx2Mode.Signaled,             # Spin | Threaded | Signaled
)
sub = sub.inspect(lambda msgs: print("received:", msgs)).collect()

pub = (
    ticker(0.1).count()
        .map(lambda n: f"tick {n}".encode())
        .iceoryx2_pub(service, variant=Iceoryx2ServiceVariant.Local)
)

Graph([pub, sub]).run(realtime=True, duration=0.5)

Both ends accept variant (Ipc for cross-process, Local for same-process), history_size, and publisher-side initial_max_slice_len.

FIX protocol

FIX 4.4 initiator, TLS initiator, and acceptor. All return (data_stream, status_stream); TLS additionally returns a sender object for sending outbound messages.

from wingfoil import fix_connect

data, status = fix_connect(
    host="fix.example.com",
    port=9876,
    sender_comp_id="MYCOMP",
    target_comp_id="BROKER",
)

messages = data.inspect(lambda msgs: [print("fix:", m) for m in msgs])
states = status.inspect(lambda ss: [print("session:", s) for s in ss])

import wingfoil as wf
wf.Graph([messages, states]).run(realtime=True, duration=10.0)

Each data tick yields a list[dict] where every dict is {"msg_type": str, "seq_num": int, "fields": [(tag, value), ...]}. Status values are "disconnected" | "logging_in" | "logged_in" or a dict {"status": "logged_out"|"error", "reason"|"message": str}.

TLS initiator (e.g. LMAX) with a sender:

from wingfoil import fix_connect_tls

data, status, sender = fix_connect_tls(
    host="fix-marketdata.london-digital.lmax.com",
    port=443,
    sender_comp_id="USERNAME",
    target_comp_id="LMXBL",
    password="secret",
)

# Send a FIX message on the session:
sender.send({
    "msg_type": "V",
    "fields": [(262, "req1"), (263, "1"), (264, "0")],
})

Acceptor:

from wingfoil import fix_accept

data, status = fix_accept(port=9876, sender_comp_id="MYCOMP", target_comp_id="INIT")

Prometheus

Expose any stream as a gauge metric on a Prometheus-compatible /metrics endpoint.

from wingfoil import ticker, Graph, PrometheusExporter

exporter = PrometheusExporter("0.0.0.0:9091")
exporter.serve()                              # bind and start the HTTP server

tick_count = ticker(1.0).count()
requests_count = ticker(0.1).count()

Graph([
    exporter.register("tick_count", tick_count),
    exporter.register("requests_count", requests_count),
]).run(realtime=True, duration=5.0)

Scrape with curl http://localhost:9091/metrics.

OpenTelemetry OTLP

Push any stream's value to an OTLP HTTP collector as a gauge metric.

from wingfoil import ticker

(
    ticker(1.0).count()
        .otlp_push(
            metric_name="wingfoil_ticks",
            endpoint="http://localhost:4318",
            service_name="demo",
        )
        .run(realtime=True, duration=10.0)
)

🛠️ Build from Source

Most users should pip install wingfoil. To build locally (e.g. to enable the iceoryx2 feature or develop against the bindings), see build.md.

git clone https://github.com/wingfoil-io/wingfoil
cd wingfoil/wingfoil-python
pip install maturin
maturin develop                               # or: maturin develop --features iceoryx2
pytest

📢 Release Status & Feedback

The Wingfoil Python module is currently a beta release. APIs are stabilising and we would love your input — especially if you:

  • are interested in contributing,
  • know of a project Wingfoil is a good fit for,
  • want to request a feature, or
  • have any feedback.

Email us at hello@wingfoil.io, open a GitHub discussion, or browse the issue tracker.

More resources:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

wingfoil-6.0.4-cp311-cp311-win_amd64.whl (9.7 MB view details)

Uploaded CPython 3.11Windows x86-64

wingfoil-6.0.4-cp311-cp311-manylinux_2_38_x86_64.whl (12.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.38+ x86-64

wingfoil-6.0.4-cp311-cp311-macosx_11_0_arm64.whl (8.8 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

wingfoil-6.0.4-cp310-cp310-win_amd64.whl (9.7 MB view details)

Uploaded CPython 3.10Windows x86-64

wingfoil-6.0.4-cp310-cp310-manylinux_2_38_x86_64.whl (12.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.38+ x86-64

wingfoil-6.0.4-cp310-cp310-macosx_11_0_arm64.whl (8.8 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

wingfoil-6.0.4-cp39-cp39-win_amd64.whl (9.7 MB view details)

Uploaded CPython 3.9Windows x86-64

wingfoil-6.0.4-cp39-cp39-manylinux_2_38_x86_64.whl (12.5 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.38+ x86-64

wingfoil-6.0.4-cp39-cp39-macosx_11_0_arm64.whl (8.8 MB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

wingfoil-6.0.4-cp38-cp38-win_amd64.whl (9.7 MB view details)

Uploaded CPython 3.8Windows x86-64

wingfoil-6.0.4-cp38-cp38-manylinux_2_38_x86_64.whl (12.5 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.38+ x86-64

wingfoil-6.0.4-cp38-cp38-macosx_11_0_arm64.whl (8.8 MB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

File details

Details for the file wingfoil-6.0.4-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: wingfoil-6.0.4-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 9.7 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for wingfoil-6.0.4-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 c88499e116c3ecd5c02b1bd8b629ebb588ab788b330162e14f5156762c17aecd
MD5 0e80dd5b81a74e6c0dcdc7f9da340bc3
BLAKE2b-256 9f86211d1ae65c1202ab529a3f83ebd4a28ce8d9d9cf0b43451322ff553222ff

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp311-cp311-manylinux_2_38_x86_64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp311-cp311-manylinux_2_38_x86_64.whl
Algorithm Hash digest
SHA256 dfeada72b6077e51644b29ccbb1146e578553cc5fd0089ddf0ea367458d0ac79
MD5 afe99b29249ed2a1a00fa88a7f56dae6
BLAKE2b-256 04015cf8949d64e4002c408410831449fb760579ecf2a10d0f6f24bbe441e19e

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b56a766df4ed6ad26fff33610bcc70f164b0372f3135fdb4ecd1cf7efafe2b3b
MD5 76c8e724b2427bec331dc341bb1be94b
BLAKE2b-256 9df7d3dcdc109a71cc46ea2144f4564e95b290a10cf1205bb1a3e8f19e5be871

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: wingfoil-6.0.4-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 9.7 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for wingfoil-6.0.4-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 e0500649105dd39b48189a1f3af248d5dc9f03bd8c6748055a097f912855e03f
MD5 ccde7c4db645dbeff113904b89334e7f
BLAKE2b-256 5cea9800404df6db9ffd217f1736e19da3d934b44d3edbaada65b535bf354846

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp310-cp310-manylinux_2_38_x86_64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp310-cp310-manylinux_2_38_x86_64.whl
Algorithm Hash digest
SHA256 6bb06f005731e3ad7e055222de8edccb17ff5a9fc3af1649cdcc1140392df25a
MD5 20891ff72c36a6f988b11f9e24e58b9c
BLAKE2b-256 dbc70210c649df305b0e8a6c28519cb42bb5f0f2207302d4c4a928b54b069f2b

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 adfc577ba15690622276577adc7437a5dcb2c245615a9e9fbb08ccb88bcbb500
MD5 8c00ce8772829700511abfecfcbab320
BLAKE2b-256 3ec09ed5d203f6e731fcb0b587c39625af5352a6c9d7884049bb844b4a9b8479

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: wingfoil-6.0.4-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 9.7 MB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for wingfoil-6.0.4-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 6c6c18d60ecec7666618861365a4efbff510c6913b39aead4d31363f932ca6c7
MD5 947ddc9b05d3643fa856d37fcd69f955
BLAKE2b-256 d9f62c87c6a4bb07845efc5bdf8896aee135751ae04f8ab1c378a098bd1e9052

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp39-cp39-manylinux_2_38_x86_64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp39-cp39-manylinux_2_38_x86_64.whl
Algorithm Hash digest
SHA256 12b2b20647233c50edb9a385ede8089a91a95b7c2fa68ac351f0a467c090a25f
MD5 1ac820209c8bfc85d1014235742ea977
BLAKE2b-256 7b0af7a74dbb5eb4318cd005ed4aa4767f6188e5b248492a822a6268ba9bd29e

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5004c1adde8708426258ca5f76447b4c9d289810177660ff288781aa7dc1a0b2
MD5 28dd2bd7076e4852fa167ce2587c36ca
BLAKE2b-256 6b825f66ee61f7478efbaa08f214850a54f90ddfb9d2e3ba94f0b86c396d87d9

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: wingfoil-6.0.4-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 9.7 MB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for wingfoil-6.0.4-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 5641d50e84f80832d4551aa684bfb82f68b2dde36e049731a031a18f3651cadd
MD5 1f25616d694df72965828d9c9d1923da
BLAKE2b-256 093b6fa8013dba51be146a5f5ad5b4951a527010c7166e2ffa7a6d5beafffbfc

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp38-cp38-manylinux_2_38_x86_64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp38-cp38-manylinux_2_38_x86_64.whl
Algorithm Hash digest
SHA256 441df6a94637de803a3c7481365f781cc1e58bb0d8753362cc84dcfce66cf013
MD5 7d9dd558279976724e63efabc6c2939a
BLAKE2b-256 a3fa969a13ad811b49c8c387ea2db3b6d541a3f2e1cc5cfd1885842731594194

See more details on using hashes here.

File details

Details for the file wingfoil-6.0.4-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for wingfoil-6.0.4-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 afab9f5426171ba4d7ca2f778e76fd55d4d150d47ab9747f938b3354d935031c
MD5 6888ae659eb31a18cf1481ed67bf1bc3
BLAKE2b-256 375a38681e28ef3e7e27916de75eb08e9e4273dcff0106c7e57b735a7aa9b08c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page