Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

CrowdyPy

The official Python SDK for Crowded Kingdoms: typed clients for the platform's one GraphQL API (identity, studio administration, world data, ck-exec) and a native UDP replication core.

CrowdyPy follows the CrowdyJS API surface (the same domains, the same two-token model, the same error codes) the way CrowdyCPP does, with Python names (mintAppToken is mint_app_token). Its realtime path is CrowdyCPP's native replication client, bound with nanobind and shipped inside the wheel. Python never touches a datagram.

v0.21.0: a send waiting across a reassignment is resent then. An actor or voxel update still waiting for its echo when the connection is reassigned is resent as soon as the new session is connected, rather than at its timeout, since its echo went to the session it left. That is its one retry; audio, text and events are never resent. CrowdyJS 18.21.0 and CrowdyCPP 0.73.0. See MIGRATION.md.

v0.20.0: a session's first awaited send is not lost. Every *_and_wait retries the first awaited send of a session once, with a fresh sequence, when it is refused UNAUTHORIZED or, for the echoed actor and voxel updates, when it times out: how a replication server older than v0.42.0 answers a session's first message (v0.42.0 holds it until the session is ready). CrowdyJS 18.20.0 and CrowdyCPP 0.72.0; no API change. See MIGRATION.md.

v0.19.0: a draining instance is left at once. Game API v2.56.0 expires the balancer's affinity cookie on a draining instance's responses; CrowdyPy forgets the expired cookie, so the next request lands on an instance that is staying. CrowdyJS 18.19.0 and CrowdyCPP 0.71.0; no API change. See MIGRATION.md.

v0.18.0: text chat and direct-message keys, and the recording switch. Game API v2.55.0 adds the app-level use_text_chat and use_direct_messages keys: without them the realtime servers refuse a player's text, channel text and direct messages with UNAUTHORIZED. A tier that grants access gets both unless applyCommunicationDefaults is false, and replayLoggingRecordsMedia leaves voice and video out of an app's recording. Deleting a managed player now erases its content, and a legal hold refuses it with LEGAL_HOLD. See MIGRATION.md.

v0.17.0: the Org-Managed Players Addendum. ck-api v2.53.0 serves org-managed players on every tier, once an admin of the organization has accepted the addendum in Studio; until then its sign-ins and refreshes answer ORG_LEGAL_ACCEPTANCE_REQUIRED, which crowdypy.errors.org_legal_acceptance_required_of reads, and client.managed_players.settings(org_id) says where the organization stands. CrowdyJS 18.17.0 and CrowdyCPP 0.69.0. See MIGRATION.md.

v0.16.0: org-managed players. An organization that runs its own accounts signs its players in itself: its server mints a player's app token with an org token, or its sign-in service signs an assertion. A device holds the first with client.portal.adopt_app_token(response) (it refuses an org token, which stays on the organization's server; there is no org-token mint wrapper) or trades the second with client.portal.exchange_managed_player_assertion(app_id, assertion), and gives the result to client.set_app_token. client.managed_players is the organization's administration. CrowdyJS 18.16.0 and CrowdyCPP 0.68.0. See MIGRATION.md.

v0.15.0: a voxel edit that waits for the server, and opcode 140 from client.udp. chunks.set_voxel(..., optimistic=False) changes nothing locally until the server's echo of the edit arrives; client.udp.send_generic_spatial sends an app-defined spatial message. CrowdyJS 18.15.0 and CrowdyCPP 0.67.4. See MIGRATION.md.

v0.14.2: CrowdyJS 18.14.0 and CrowdyCPP 0.67.3. player_wallet.charges() is deprecated: read transactions(), whose usage_debit entries are the usage charges.

v0.14.1: the exec socket names a paused app and a switched-off app or type. AppPaused, AppDisabled, and TypeDisabled. Still CrowdyJS 18.13.0 and CrowdyCPP 0.66.0.

v0.14.0: the economy (CrowdyJS 18.13.0, CrowdyCPP 0.66.0). kit.player, the caller's own player hub, and its views kit.inventory, kit.wallet, kit.progression, kit.achievements, kit.quests, kit.crafting, kit.loot and kit.production; markets by name: kit.shops.at(key), kit.market.at(key) and kit.trades.at(key). It lives in hub state and is not a ledger. A change refused unavailable is sent again with its action id. They need ckx-sdk 0.12.1 in the tier's compute toolchain (dev: v1.15.0).

v0.13.0: the genre starters (CrowdyJS 18.12.0, CrowdyCPP 0.65.0). Nine more kit modules, one per ck-exec genre starter: kit.leaderboards.board(name), kit.tables.table(key) (the caller's hand as private state), kit.tactics.battle(key), kit.encounters.encounter(key), kit.minigames.duel(key), kit.instances.run(key), kit.arenas.arena(key), kit.racing.race(key) / ball(key) and kit.territory.map(key) / zone(key), in both clients. They need a compute toolchain with ckx-sdk 0.11.0 on the tier.

v0.12.0: the Game Kit on ck-exec (CrowdyJS 18.11.0, CrowdyCPP 0.64.0). client.kit(app_id) gains typed clients for the ck-exec starter hubs, the client half of the game kit whose server half is ckx_sdk::kit: kit.world (conditions and resource nodes mirrored, harvests, liveops for developers), kit.matchmaking.queue(name) (parties matched whole), kit.sessions.open(key) (lobby to result), kit.npcs.area(key) (mobs, NPCs, players' pets), kit.topology (compose, check, build and deploy the starters), and kit.spectate, kit.emotes and kit.shards. They share one exec connection (kit.runtime) that paces calls under the gateway's limit, resends only what is safe and mirrors topics with resync on gaps, epochs and reconnects; a hub's refusal is a KitError with its code. Both clients have it: the blocking one runs a mirror's resync beside the connection's reader thread. Exec reconnects wait with jitter. See MIGRATION.md.

v0.11.0: access that ends ends for good, and channel and team bans (CrowdyJS 18.10.0, CrowdyCPP 0.63.0). A host's 4403 close (ck-exec 0.16: the player was suspended, revoked, signed out or blocked) is final: ExecConnection.on_access_ended hears the reason, the call in flight fails Denied, and the connection does not redial. client.channels.ban / unban and client.teams.ban / unban manage bans, and account_blocked_of / group_member_banned_of read the two refusals. See MIGRATION.md.

v0.10.0: the input log says what it lost (CrowdyJS 18.9.0, CrowdyCPP 0.62.0). Every session from client.input_log.sessions carries missingRecords, the inputs the replication server accepted that never reached the log, which needs the Game API release after v2.40.2. Its docstrings name the new end reasons (paused among them), the two read refusals worth retrying with the same cursor, and how to stop a read nobody will see: cancel its task, which closes the request and frees its server read share. See MIGRATION.md.

v0.9.1: the input log's session filter sends userId as a string, and its reads document when to retry. See the 0.9.1 bullet below; 0.9.0 added the SDK a build compiled against.

v0.8.0: voice, channel audio, wide voxels, and pause and access refusals (CrowdyJS 18.7.0, CrowdyCPP 0.60.0).

  • Voice: crowdypy.media's voice helpers (an optional 10-byte header per codec frame, VoicePacketizer, VoiceJitterBuffer), and client.udp.send_channel_audio() with the channel_audio handler, which reaches every member of a channel wherever they are (party and guild voice).
  • World Stores: ChunkStore keeps voxel edits the 16x16x16 one-byte grid cannot hold in an overlay, and applies the echo of your own edit once. session.on("voxel_update") and session.on("generic_spatial") reach a game that keeps its own world.
  • Refusals: crowdypy.is_app_paused() reads the runtime gate that tokens and the bootstrap carry, and app_paused_of, access_refusal_of and actor_exists_of read the new refusals.
  • New calls: users.player_profile(s), app_access.suspend and unsuspend, and exec.restart_type.
  • 0.9.0: every build (exec.build, build_status, wait_for_build and the mod builds) carries sdk_version, the ckx-sdk (CLIENT half: crowdy-client-sdk) version the platform compiled it against, whatever the crate names. It needs ck-api v2.40.2, since the build documents select it.
  • 0.8.0 needs the ck-api release after v2.39.0, since the token mutations select runtimeGate. Channel audio and the voxel echo need replication server v0.37.0.
  • 0.7.0 brought the input log (client.input_log.sessions() and messages(), and replayLoggingEnabled). 0.6.0 brought distance-limited channel messages (udp.send_ranged_channel_message()) and the terms gate (auth.record_player_consents()).
  • 0.5.1 made ChunkStore.hydrate() keep every recorded voxel edit (voxelStates) and ensure_around() keep a chunk it already loaded.
  • 0.5.0 brought the ck-exec gateway check (client.exec.connect() sends the connect token only to a gateway on the game API's estate, and reports a refusal as Denied) and open grids (game_apps.open_permissions() and set_open_permissions()).
  • 0.4 brought the headless Crowdy Studio (crowdypy.studio), player-host observation (crowdypy.player_host), the roots CrowdyCPP covers beyond CrowdyJS, and the strict parity gate (docs/parity-matrix.md has no gaps); 0.3.0 the World Stores, the Game Kit, ck-exec and subscriptions; 0.2.0 native UDP replication (client.udp); 0.1.0 the GraphQL client.

See MIGRATION.md.

Install

pip install crowdypy

Wheels: CPython 3.12+ (one abi3 wheel per platform) and free-threaded CPython 3.14, on Linux x86_64 / aarch64, macOS arm64 / x86_64 and Windows x64. OpenSSL is linked statically; nothing else native is needed. docs/compatibility.md has the details, including the tier versions below.

Each tier of the platform has its own release line, and a build defaults to its own tier's API origin (crowdypy.CROWDY_DEFAULT_TIER says which):

Tier PyPI version Pin
dev X.Y.Z.devN crowdypy==0.4.0.dev1
test X.Y.ZrcN crowdypy==0.4.0rc1
prod X.Y.Z crowdypy==0.4.0

pip skips pre-releases unless a requirement names one, so a prod range never picks up a dev or test build. The same wheels and the sdist are attached to each GitHub release, and pip installs one from its URL (pip install https://github.com/CrowdedKingdoms/CrowdyPy/releases/download/<tag>/<wheel>).

Quick start

import asyncio

import crowdypy

API = "https://ck.dev.crowdedkingdoms.com"


async def main() -> None:
    # The identity client: sign-in, account and studio calls, minting.
    async with crowdypy.AsyncCrowdyClient(http_url=API) as identity:
        await identity.auth.login("player@example.com", "correct-horse-battery")
        minted = await identity.portal.mint_app_token("42")

    # The game client: one per app, at the app's own datacenter.
    async with crowdypy.AsyncCrowdyClient(
        http_url=minted.game_api_url or API, discovery_url=minted.discovery_url
    ) as game:
        game.set_app_token(minted)
        print(await game.server_status.server_with_least_clients())


asyncio.run(main())

Without an event loop, crowdypy.sync.CrowdyClient has the same methods, without await:

from crowdypy.sync import CrowdyClient

with CrowdyClient(http_url=API) as identity:
    identity.auth.login("player@example.com", "correct-horse-battery")
    print(identity.users.me())

Two tokens, two clients

There is one API origin but two tokens, as in every Crowded Kingdoms SDK:

  1. Sign-in (auth.login, a magic link, or social/OIDC) yields an identity session token: account, studio administration and minting. It is not accepted for gameplay.
  2. Gameplay needs a short-lived app-scoped token per app (portal.mint_app_token(app_id)), which is also the HMAC key for native UDP. Refresh it with client.refresh_gameplay_token() (concurrent callers share one refresh). It is refused with LEGAL_ACCEPTANCE_REQUIRED until the player's agreement to the legal documents and age attestation are stored: show both checkboxes, then call auth.record_player_consents(accept_legal=True, attest_age_of_majority=True).
  3. Build one identity client and one client per game. The game client points at the app's datacenter (game_api_url) with discovery_url set, so it can find the app again if that instance stops answering.

Persist them the same way: FileTokenStore.session_path(directory, api_origin) names the session file (one per origin, shared by every game) and FileTokenStore.app_path(directory, app_id) the gameplay one (one per app):

from crowdypy import FileTokenStore

identity = crowdypy.AsyncCrowdyClient(
    http_url=API, token_store=FileTokenStore(FileTokenStore.session_path(state_dir, API))
)

CrowdyPy sends no Origin header, so direct sign-in is served to it; hosted browser sign-in (portal.signIn in CrowdyJS) is a browser flow and is not part of this SDK.

Errors

Every error is a crowdypy.CrowdyError. A GraphQL refusal is a CrowdyGraphQLError with the server's stable code (error.code == "FORBIDDEN") and extensions; HTTP, network and timeout failures have their own classes. CrowdyAppUnavailableError (the app's datacenter is not serving) and CrowdyUserCodeFaultError (a player module faulted; player_fault_of(error) reads the fault) mirror CrowdyJS. A WRONG_DATACENTER refusal moves the client to the app's datacenter and retries once, by itself.

A paused app (its organization ran out of funds, hit a spend cap, or let a subscription lapse) still mints a token, so check crowdypy.is_app_paused(minted.runtime_gate) before entering the world, and tell the player it is paused. Replication then refuses sends with UDP error 33 (APP_PAUSED). crowdypy.app_paused_of(error), access_refusal_of(error) (ACCESS_REVOKED, ACCESS_SUSPENDED with suspended_until, ACCESS_NOT_GRANTED) and actor_exists_of(error) read those refusals. None of them clears by retrying.

Replication

minted = await identity.portal.mint_app_token("42")
async with crowdypy.AsyncCrowdyClient(
    http_url=minted.game_api_url or API, discovery_url=minted.discovery_url
) as game:
    await game.udp.connect(minted)  # assign a server, open the socket
    game.udp.subscribe({"actor_update": lambda n: print(n.uuid, n.chunk, n.payload)})
    await game.udp.send_actor_update((0, 0, 0), my_uuid, pose_bytes)
    echo = await game.udp.send_actor_update_and_wait((0, 0, 0), my_uuid, pose_bytes)

For a game loop, use the connection underneath: send a frame's entities in one call, and read whole batches.

conn = game.udp.connection
conn.send_actor_updates(chunks, uuids, poses, stride=88)  # numpy (n, 3) int64, n x 32 octets
async for batch in conn.batches():
    actors = batch.types == crowdypy.wire.MessageType.ACTOR_UPDATE_NOTIFICATION
    positions = batch.chunks[actors]  # a view, not a copy

crowdypy.replication.ReplicationConnection is the same for code without an event loop: wait() and then poll() from your own loop.

Voxel positions and types are the app's signed 16-bit values, and a voxel state is at most 1,024 bytes (InvalidArgument otherwise, nothing sent). Replication server v0.37.0 echoes every accepted voxel edit back to its sender as a voxel_update.

Voice

send_audio_packet reaches players near a chunk and carries whatever bytes it is given; a game with a voice format of its own keeps it. The voice helpers in crowdypy.media are an optional format that every Crowded Kingdoms SDK shares, byte for byte. Each packet is a 10-byte header (version 1, the codec, a u16 seq, a u32 timestamp in codec samples, the frame's duration and two talk-spurt flags) followed by one codec frame. VoicePacketizer numbers one sender's frames. VoiceJitterBuffer puts each sender's packets back in order and plays them out 60 ms after the first packet of a talk spurt arrived. It reports a frame that never came as a gap, drops one that arrives after its playout time, and holds at most 64 frames a sender.

send_channel_audio reaches every member of a channel wherever they are (party or guild voice), at most 1,024 bytes a packet. The sender needs the channel's send_voice (members_can_speak=True on creation gives it to the member role) and the player's use_voice_chat. There is no echo, and members receive channel_audio:

from crowdypy.media import VoiceCodec, VoiceJitterBuffer, VoicePacketizer

party = VoicePacketizer(VoiceCodec.OPUS, 20)
# Every 20 ms while the player talks (`opus_frame` from your own encoder):
await game.udp.send_channel_audio(channel_id, my_uuid, party.packetize(opus_frame, last=released))
# ...and party.skip() for every 20 ms of silence that is not sent.

voices = VoiceJitterBuffer()
game.udp.subscribe({"channel_audio": lambda n: voices.push(f"{n.channel_id}:{n.uuid}", n.payload)})
for slot in voices.poll():  # at least once a frame, from your audio clock
    if slot.gap:
        conceal(slot.key, slot.frame_ms)  # the frame never came
    else:
        play(slot.key, slot.codec, slot.frame)

No codec ships with CrowdyPy, and the wheel links none: which codec an app uses (Opus, or G.711 µ-law where it has no Opus), and the library that encodes and decodes it, is the app's choice. Where a voice sits in the world (panning, distance attenuation) is the game's too.

World Stores

from crowdypy.codecs import f32, struct_codec, u16
from crowdypy.stores import create_world_session

pose = struct_codec({"x": f32(), "y": f32(), "z": f32(), "yaw": u16()})
session = create_world_session(game, app_id, actor_codec=pose, host=True, save=True)
session.self.join((0, 0, 0), {"x": 0.0, "y": 64.0, "z": 0.0, "yaw": 0})
session.actors.on_join(lambda actor: print("joined", actor.uuid, actor.value))
asyncio.create_task(session.run())  # tick 60 times a second

snapshot = session.actors.snapshot()  # once a frame: every actor at once
states = pose.decode_many(snapshot.state_offsets, snapshot.state_data)  # numpy, no loop

session.chunks is a helper for 16x16x16 chunks with one byte per voxel. An edit that grid cannot hold (a type outside 0-255, a position outside 0-15) is kept in the chunk's overlay(), and voxel_type_at reads it first. The echo of your own set_voxel is not applied a second time; with optimistic=False the edit is applied only when that echo arrives, and nothing is queued for write-back. A game with other addressing reads every edit from session.on("voxel_update", ...), which includes those echoes.

Game Kit

client.kit(app_id) drives the ck-exec starter hubs (the server half is ckx_sdk::kit), with the same modules as CrowdyJS's client.kit(appId):

kit = game.kit(app_id)
await kit.world.conditions.start()  # mirrored: time of day, weather, liveops modifiers
queue = kit.matchmaking.queue("ranked")
queue.on_matched(lambda session: print("matched into", session))
await queue.join(1200)
watching = asyncio.create_task(queue.watch())  # asks while the player waits
try:
    await kit.npcs.area_at(12, -3).attack(4)
except KitError as e:
    if e.code == "cooldown":
        ...

kit.world, kit.matchmaking, kit.sessions, kit.npcs and kit.topology (compose, check, build and deploy the starters) share one exec connection (kit.runtime): it paces calls under the gateway's 120 per 10 s, sends a call again only when that is safe (it did not run, or it carries an action_id the hub answers once), and its mirrors (HubState, CollectionMirror, PrivateState) take a new snapshot after a gap, another epoch or a reconnect. kit.spectate, kit.emotes and kit.shards are the client conventions, and kit.social the parties, guilds and chat rooms. The blocking client's kit is the same, with blocking calls.

Crowdy Studio

from crowdypy.studio import CrowdyStudioController

studio = CrowdyStudioController.for_client(game, app_id=app_id, grid_id=grid_id)
await studio.initialize()  # opens the first project
studio.update_file("SERVER", "src/lib.rs", source)  # autosaves
result = await studio.test_draft()  # build, deploy and switch on the mod
print(result.status, studio.get_state().build_output)

A CLIENT target runs in a host you pass as broker_factory; the browser Studio runs it in a Web Worker.

Performance

Python does no work per datagram. Receive, HMAC verification and decoding happen on CrowdyCPP's network thread, which never takes the GIL; Python sees one batch object per poll. Sends release the GIL, and a batch releases it once for the whole batch. An asyncio loop is woken through a socket, not by polling. Measured against CrowdyCPP on the same machine (benchmarks/README.md): a 200-entity batch costs 1.06x CrowdyCPP's own send path per entity, Python takes in two million verified notifications a second, a notification reaches an asyncio handler 47 µs after it hits the wire (p50), and a 60 Hz loop stays within 0.2 ms of its schedule while receiving 60,000 a second.

Development

uv sync                       # builds the extension (CMake, a C++20 compiler) and installs dev tools
uv run pytest tests/unit
uv run ruff check . && uv run ruff format --check . && uv run mypy

The live suites in tests/e2e/ run against a deployment when the CROWDY_E2E_* variables are set; docs/e2e-coverage.md lists them, how to configure them and the last live runs.

The gates CI runs, all from a clean checkout:

Gate Command
Vendored CrowdyCPP is the pinned commit's tree python scripts/vendor_crowdycpp.py --check
schema.gql and operations are CrowdyJS's at the pin python scripts/schema_sync.py --check
Generated code is current python scripts/codegen.py --check
The blocking client is generated from the async one python scripts/unasync.py --check
Parity with CrowdyJS python tools/parity/parity.py --crowdyjs ../CrowdyJS --check docs/parity-matrix.md
No internal names in the tree or the artifacts python scripts/ci/check_content_policy.py

AGENTS.md covers maintenance: re-pinning CrowdyJS and CrowdyCPP, the tier branches and the release path.

License

MIT. Wheels also contain CrowdyCPP (MIT), yyjson (MIT) and OpenSSL (Apache-2.0).

Metadata

Release files for crowdypy 0.21.0.dev1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for crowdypy 0.21.0.dev1
File Size Uploaded Provenance
crowdypy-0.21.0.dev1.tar.gz 1.4 MB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for crowdypy 0.21.0.dev1
File
crowdypy-0.21.0.dev1-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ x86-64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_aarch64.whl CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ ARM64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.26+ ARM64, Linux glibc 2.28+ ARM64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_x86_64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ x86-64 Details
crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details
crowdypy-0.21.0.dev1-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_x86_64.whl CPython 3.12 abi3 Linux musl 1.2+ x86-64 Details
crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_aarch64.whl CPython 3.12 abi3 Linux musl 1.2+ ARM64 Details
crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details
crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl CPython 3.12 abi3 Linux glibc 2.26+ ARM64, Linux glibc 2.28+ ARM64 Details
crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_x86_64.whl CPython 3.12 abi3 macOS 11.0+ x86-64 Details
crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details

Total release size: 42.2 MB

Release files / crowdypy-0.21.0.dev1.tar.gz

Download URL crowdypy-0.21.0.dev1.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
9f02b3808ad97236ccb67c5ae5c5c131e33255c0b7723f0bb79c663a77d247df
BLAKE2b-256 checksum
How to use checksums
4ce23b0750c05a6bea0a6933db50064e5844089587ce85ac3e8cd65f87a1c1f6
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-win_amd64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-win_amd64.whl
Size 2.6 MB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
93a7ec36dd6de385fdc66b19b09a75b8721e0bb3c648c1d5fe2ed7fd7c1dce9d
BLAKE2b-256 checksum
How to use checksums
08a9008f06bac594f17f6c223b0de204302aabf7b90066d7ffbc78db44e0f228
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_x86_64.whl
Size 3.0 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ x86-64
SHA-256 checksum
How to use checksums
e6eb4854fff87442fc4113fab29582b6a57f2a53172445dec647b7c7a23559c9
BLAKE2b-256 checksum
How to use checksums
6d116e9d29130619225e17e34199174ae8802f2695a201b07c048aabf181ade0
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_aarch64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-musllinux_1_2_aarch64.whl
Size 3.3 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux musl 1.2+ ARM64
SHA-256 checksum
How to use checksums
56f9eb291db27c01b036954213416a74e885a726f2f82eaa402ac2aec4ee8722
BLAKE2b-256 checksum
How to use checksums
9b2aca9cd73fe1537f8a0c8c77ccdd8b2b87d01e72553b83e6910412804da34a
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.9 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
92b67ebfe88a083088b34308d4aeb4e64956abc213379f478b7c63b57d3c591d
BLAKE2b-256 checksum
How to use checksums
1be5d786a589022c611a1e84167439577752d340efe749b7335d56fd733cd1aa
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
Size 3.2 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64
SHA-256 checksum
How to use checksums
04695e00e51edd1a505b193a57ad1410d1e490e8f70c9bdf3ba6743c0979ecfe
BLAKE2b-256 checksum
How to use checksums
8d58fad1806200e23d71dd050eeb5eb67fe03cfe468b68bbffa4da4c8383757e
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_x86_64.whl
Size 2.6 MB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
f87caaed5424566a8fc51be1c21fbcaec607511b0f13ecdb3fe2720842788ec4
BLAKE2b-256 checksum
How to use checksums
57f338f14acb52483711a081ad5a3a959550cd5e78d8fe0aa398a4eb29c15e3a
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_arm64.whl

Download URL crowdypy-0.21.0.dev1-cp314-cp314t-macosx_11_0_arm64.whl
Size 2.9 MB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
130582db33f583e136f902f8a26ee6a5ad176cbeadac11ed74e9af989e03c7d9
BLAKE2b-256 checksum
How to use checksums
de3cec82d2d1c324d41b939e8e5ef22cd80250279970f88728c8e7c685bd0814
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-win_amd64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-win_amd64.whl
Size 2.5 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f3a065caa7033efe82d5aeff6978e3b8e8b9cb79dde8f09944644f4b00434379
BLAKE2b-256 checksum
How to use checksums
22ddd8e6b9e23a2f0176a59b98224f6de785aac6d1556716154e7fa40579f9a2
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_x86_64.whl
Size 3.0 MB
Tags CPython 3.12 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
53ae0888386d2822cccae4f552e9d767f49b957ca40107ad07d0dcb9fdad24b8
BLAKE2b-256 checksum
How to use checksums
a21ade5206aecb961bbb3577e78fdd6dfe8890f947a7b21fcb17e3422c5161ac
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_aarch64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-musllinux_1_2_aarch64.whl
Size 3.3 MB
Tags CPython 3.12 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
fa95bb3691782599317ca6f4b9da23a0ab5b6604a6776b0ee0a18040e97d6b61
BLAKE2b-256 checksum
How to use checksums
39cb38a38a1b0e96f3d4ef169341205429ba386c5ac70cdc6a4a37ee6ed14a18
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 2.9 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
9d498257051c637cf30004cddbba7123be94dfc8617eac7e780c8a16dd5d7d72
BLAKE2b-256 checksum
How to use checksums
4616bc03f5ba427bcd5d109f400b2a22bce6b99696a6923fa5f744b94cc6f0e0
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
Size 3.2 MB
Tags CPython 3.12 Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
dbf147e7db6c07b7cce821dc33ca50b0831909e7bfe7b0f1d4c2316c5af7a3d2
BLAKE2b-256 checksum
How to use checksums
8b6f7f72a4a5771a55af5ec3613401a8cea08d87b5f16189261f6d4d537a1b5d
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_x86_64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_x86_64.whl
Size 2.6 MB
Tags CPython 3.12 abi3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
f2b13376bfe89a2a8c5653f52a47e95dd4ec1491d1bff7c1a9e87144deebf3f0
BLAKE2b-256 checksum
How to use checksums
85e5f5a6173cb9ae2c7f8ea72f03c390922625aaf00e33d2829ec09cd418af03
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 Oct 25, 2026.

Transparency log

Release files / crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_arm64.whl

Download URL crowdypy-0.21.0.dev1-cp312-abi3-macosx_11_0_arm64.whl
Size 2.9 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
98cf83e9f0d44e6fccb3a9acbb3497463583b66acc4dc092ede2923520161a16
BLAKE2b-256 checksum
How to use checksums
07f7747984c364b24246ba7d7f4db0691ffd5630a0feb6ef46556c09812ce582
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 Oct 25, 2026.

Transparency log

Security for crowdypy 0.21.0.dev1

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 15 files in this release have been uploaded with provenance metadata.

Select from 15 files

Attestation for crowdypy-0.21.0.dev1.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 Oct 25, 2026.

Transparency log

A 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.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page