Rewloy Python
Rewloy API'nin resmî Python kütüphanesi.
Durum: önizleme (0.x), PyPI'da yayımlandı. API kararlı; kütüphane arayüzü 1.0'a kadar değişebilir.
Rewloy, işletmelerin dijital sadakat kartlarını müşterinin telefonuna koyar. Kart türleri damga, puan, VIP, cashback, hediye kartı, kupon ve indirimdir:
- iPhone'da Apple Cüzdan;
- Android'de Rewloy Cüzdan ve Google Cüzdan;
- her yerde web kartı.
Kasada QR okutulur; bakiye, ödül ve kampanyalar kartın kendisinde güncellenir. Panelde yapılabilen her şey Rewloy API v1 ile de yapılabilir; bu kütüphane onu Python'dan kullanır:
- Tam tipli. API'nin her işlemi,
operationIdadının snake_case hâliyle bir metottur (passAction→pass_action). İstek gövdeleri, sorgular ve yanıtlar OpenAPI belgesinden (openapi.json) üretilenTypedDicttipleriyle gelir;mypy --strictgeçer. CI belgeyi her gün okur ve değişince yeniden üretir. - Bağımlılıksız. Python 3.9 ve üstü; yalnız standart kütüphane (
urllib,json,hmac). Bağlantı havuzu ve HTTP/2 isteyen içinhttpxtaşıması isteğe bağlıdır. - Güvenli tekrar. Geçici hatalarda ölçülü yeniden deneme; kasa işleminde
ve kampanyada
Idempotency-Key. - Ötesi: sayfalama, canlı akış (SSE), webhook imzası doğrulama, kullanımdan kalkma uyarıları.
Kurulum
Python 3.9 ya da üstü gerekir:
pip install rewloy
httpx taşıması için: pip install "rewloy[httpx]".
Başlarken
import os
from rewloy import Rewloy
rewloy = Rewloy(api_key=os.environ["REWLOY_API_KEY"])
kart = rewloy.get_pass("ABCD-EFGH-JKLM")
print(kart["type"], kart["balance"], kart["rewardReady"])
Her işlem, adı operationId'nin snake_case hâli olan bir metottur
(API referansı; OPERATION_IDS ve
METHOD_NAMES ikisini eşler). Argümanlar:
- adresteki parametreler konumsaldır:
get_pass(seri); query: sorgu parametreleri (sözlük);body: JSON gövde (sözlük);merchant:Rewloy-Merchantbaşlığı;idempotency_key:Idempotency-Keybaşlığı (kasa işlemi ve kampanya);timeout(saniye) vemax_retries.
Sorgu ve gövde sözlükleri API'deki adlarıyla yazılır (programId,
kvkkConsent); anahtarlar çevrilmez. Metot yanıttaki datayı döndürür:
- bir
TypedDictya da liste; yanıtı olduğu gibi alırsınız, API'nin sonradan eklediği bir alan hemen sözlüğünüzdedir; - sayfalı listelerde
Page(sayfa.data,sayfa.meta); - gövdesiz yanıtta (
204)None; - dosyada (QR, harita, CSV,
.pkpass)bytes.
Tipler rewloy.types altındadır: IssuePassBody, GetPassData,
ListCustomersItem, ErrorCode… Çalışma anında yüklenmemeleri için
(import rewloy onları yüklemez; yaklaşık 80 ms tutar) yalnız açıklamada
kullanıyorsanız TYPE_CHECKING altında içe aktarın:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from rewloy.types import IssuePassBody
Kimlik
| İstemci | Ne için |
|---|---|
Rewloy(api_key="rwk_…") |
API anahtarı: kasa, e-ticaret, kendi sisteminiz |
Rewloy(staff_session="rws_…", merchant=…) |
ekip oturumu: bir kişinin işletme uygulaması |
Rewloy(holder_session="rwh_…") |
kart sahibi oturumu: Rewloy Cüzdan gibi müşteri uygulamaları |
Rewloy() |
kimlik istemeyen uç noktalar: giriş, katılım, kod |
merchant, ekip oturumu birden fazla işletmede koltuk taşıyorsa hangi işletme
için çalıştığını söyler (Rewloy-Merchant). Her çağrıda merchant= ile
değiştirilebilir. Oturumlar kimliksiz bir istemciyle açılır:
oturum = Rewloy().login(body={"email": eposta, "password": parola})
ekip = Rewloy(staff_session=oturum["token"], merchant=isletme_id)
if oturum["mfaRequired"]:
ekip.prove_mfa(body={"code": "123456"})
Bir işlem istemcinin kimlik türünü kabul etmiyor ama kimliksiz de çalışıyorsa
(örneğin login), istemci onu kimliksiz çağırır. API, işlemin kabul etmediği
bir kimliği reddeder (CREDENTIAL_NOT_ALLOWED). Kimlik reprde görünmez.
Diğer seçenekler:
base_url(varsayılanhttps://app.rewloy.com);timeout(saniye; varsayılan 60,0sınırsız);max_retries(2);transport: HTTP katmanı (bkz. Taşıma);user_agent: gönderilenUser-Agenta eklenir, örneğin"KasaPOS/4.2";sleep: yeniden denemeler arasındaki beklemeyi değiştirir (testler için).
İstemci iş parçacıkları arasında paylaşılabilir. with Rewloy(...) as rewloy:
ya da rewloy.close() taşımanın tuttuklarını bırakır.
Kart vermek ve kasada işlem
sonuc = rewloy.issue_pass(
body={"programId": program_id, "email": "ayse@ornek.com", "firstName": "Ayşe", "kvkkConsent": True},
)
seri, kart_adresi = sonuc["serial"], sonuc["cardUrl"]
islem = rewloy.pass_action(
seri,
body={"action": "earn-stamps", "locationId": sube_id, "count": 1},
idempotency_key=f"fis-{fis_no}",
)
if islem.get("duplicate"):
print("Bu fiş zaten işlenmiş")
pass_action, send_campaign ve issue_pass bir Idempotency-Key alır.
Verilmezse kütüphane bir UUID üretir ve aynı çağrının her denemesinde
aynısını gönderir. Kasada fiş numarası gibi kendi anahtarınızı vermek
daha iyidir: uygulama çöküp yeniden başlasa bile aynı fiş ikinci kez işlenmez,
aynı anahtarla tekrar ilk sonucu duplicate: true ile döndürür.
Sayfalama
for musteri in rewloy.paginate("listCustomers", query={"consent": "yes", "limit": 200}):
print(musteri["displayName"], musteri["identifiers"])
paginate sayfalı her listeyi (page/limit ve meta) öğe öğe dolaşır ve
son sayfada durur; tembeldir, bıraktığınız yerde istek de durur. Adreste
parametresi olan listelere path={"id": …} verilir. Tek bir sayfa için
metodun kendisi yeter: sayfa = rewloy.list_customers(query={"page": 2})
(sayfa.data, sayfa.meta).
Canlı akış
with rewloy.live_feed() as akis:
for olay in akis:
if olay.event == "event":
ev = olay.json()
print(ev["kind"], ev["location"], ev["program"], ev["delta"], ev["unit"], ev["name"])
live_feed (işletmenin tezgâh akışı) ve holder_card_events (kart sahibinin
kartındaki değişiklik) sunucu olayları (text/event-stream) yayınlar.
rewloy.stream("liveFeed", …) aynı işi görür. Her olay event, data ve
id taşır; json() datayı ayrıştırır.
- Yeniden bağlanma. Bağlantı koparsa akış kendiliğinden yeniden bağlanır:
sunucunun
retry:süresi kadar bekler, bir olayidtaşıdıysaLast-Event-IDgönderir.reconnect=Falsebunu kapatır. - Sessiz bağlantı. API 25 saniyede bir
: hbgönderir; 60 saniye hiç veri gelmezse bağlantı kopmuş sayılır (idle_timeout=). - Durdurmak: döngüden
break(bağlantı hemen kapanır),withbloğundan çıkmak ya da başka bir iş parçacığındanakis.close(). - Bitiren hatalar. Yeniden bağlanmanın düzeltemeyeceği bir hata (
401,403,404) akışıRewloyErrorile bitirir.
Webhook doğrulama
Rewloy her teslimi imzalar:
Rewloy-Signature: t=<unix saniye>,v1=<hex HMAC-SHA256(sır, "<t>.<ham gövde>")>
verify_webhook imzayı ham gövdeyle ve webhook oluşturulurken bir kez
gösterilen sırla (whsec_…) doğrular:
- karşılaştırmayı
hmac.compare_digestile sabit sürede yapar; tşimdiden 300 saniyeden (tolerance=) uzaksa reddeder;- gövdeyi ayrıştırılmış olarak (
dict) döndürür.
Tutmazsa WebhookSignatureError atar: 400 ile yanıtlayın ve hiçbir işlem
yapmayın. Gövde mutlaka ham olmalıdır (str ya da bytes). JSON olarak
ayrıştırılıp yeniden yazılan bir gövde imzayı tutturmaz; ayrıştırılmış bir
dict verirseniz TypeError alırsınız.
Flask:
import os
from flask import Flask, request
from rewloy import WebhookSignatureError, verify_webhook
app = Flask(__name__)
@app.post("/rewloy/webhook")
def rewloy_webhook():
try:
olay = verify_webhook(
request.get_data(),
request.headers.get("Rewloy-Signature"),
os.environ["REWLOY_WEBHOOK_SECRET"],
)
except WebhookSignatureError:
return "", 400
# Rewloy-Delivery bir teslimin her denemesinde aynıdır: işlediyseniz atlayın.
if daha_once_islendi(request.headers.get("Rewloy-Delivery")):
return "", 200
if olay["type"] == "pass.activity":
print(olay["data"]["card"], olay["data"]["kind"], olay["data"]["delta"])
return "", 200
FastAPI (Django'da ham gövde request.bodydir):
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
@app.post("/rewloy/webhook")
async def rewloy_webhook(request: Request) -> dict[str, bool]:
try:
olay = verify_webhook(await request.body(), request.headers.get("rewloy-signature"), SIR)
except WebhookSignatureError:
raise HTTPException(status_code=400)
...
return {"ok": True}
Başlıklar:
Rewloy-Event: olay türü (pass.issued,pass.activity,pass.voided,webhook.test); gövdedekitypeile aynı.Rewloy-Delivery: teslimin kimliği. Teslim "en az bir kez"dir: çift gelen teslimi bununla ayıklayın.
Gövde kişinin iletişim bilgisini taşımaz; kişiyi customer_id ile API'den
okuyun. 2xx dışı bir yanıt yaklaşık 45 saat boyunca 8 kez yeniden denenir ve
her deneme yeni bir t ile imzalanır. Sonuç PassEvent ya da
WebhookTestEvent tipindedir: olay["type"] ile mypy türü daraltır, bilinmeyen
yeni bir tür için bir else dalı bırakın. Kendi işleyicinizi test etmek için
sign_webhook(govde, sir) aynı başlığı üretir.
Hatalar ve yeniden deneme
from rewloy import RateLimitError, RewloyError
try:
rewloy.pass_action(
seri,
body={"action": "spend", "locationId": sube_id, "amountMinor": 5000},
idempotency_key=f"fis-{fis_no}",
)
except RateLimitError as err:
print(f"{err.retry_after} saniye sonra yeniden deneyin")
except RewloyError as err:
if err.code == "INSUFFICIENT_BALANCE":
print(err.detail)
else:
raise
RewloyError şunları taşır:
status: HTTP durumu;code: API'nin sabit kodu (hata kodları); kodunuz buna göre davranmalı (rewloy.types.ErrorCodebugünkü kodları sayar);title: kodun katalogdaki başlığı;detail: API'nin açıklaması (Türkçe, değişebilir);details: varsa ayrıntı; doğrulama hatasında[{"field", "rule", "message"}];request_id:x-request-id; destek talebinde bunu verin;body,headers,docsveoperation.
Alt sınıflar:
RateLimitError:429;retry_aftersaniye;RewloyConnectionError: yanıt gelmedi (status0,codeCONNECTION_ERROR);RewloyTimeoutError: zaman aşımı (TIMEOUT).
Rewloy'un olmayan bir hata gövdesi (örneğin bir vekil sunucunun 502 sayfası)
HTTP_502 gibi bir kodla gelir. Yanlış kullanım (yanlış önekli bir anahtar,
eksik adres parametresi) Python'un ValueErrorı ya da TypeErrorıdır.
Yeniden deneme. Şunlar en çok max_retries kez (varsayılan 2) yeniden
denenir: bağlantı hatası, zaman aşımı, 429, 502, 503, 504 ve
Cloudflare'in 520–524 hataları.
- Bekleme: üstel ve rastgele (0,5 sn, 1 sn, 2 sn… en çok 8 sn); yanıt
Retry-Aftertaşıyorsa o kadar.Retry-After60 saniyeden uzunsa beklenmez, hata size gelir. - Yalnız tekrarı güvenli istekler:
GET,PUT,DELETEveIdempotency-KeytaşıyanPOST. İlk istek hâlâ işlenirken gelen409 IDEMPOTENCY_IN_PROGRESSde beklenip yeniden denenir. DiğerPOSTvePATCHistekleri hiç tekrar edilmez. - Süre: her deneme
timeout(varsayılan 60 sn) içinde bitmelidir; süre gövdenin tamamını kapsar.
Kullanımdan kalkma
Kalkacak bir uç nokta en az 180 gün önceden duyurulur. O süre boyunca her
yanıtı Deprecation, Sunset ve Link başlıklarını taşır.
- Uyarı. Kütüphane her işlem için bir kez
warnings.warnile birDeprecationWarningyayar. Uyarı işlemi,Sunsettarihini ve değişiklik günlüğündeki kaydı söyler; satır olarak sizin çağrınızı gösterir, bu yüzden Python'un varsayılan süzgeci onu__main__kodunda gösterir. - Tipler. O metodun belge dizgisi (docstring) kaldırılacağını söyler; kalkacak yanıt alanları da metodun belgesinde ve tiplerde işaretlidir.
- Yönetmek.
python -W defaulther yerde gösterir;-W ignore::DeprecationWarningya dawarnings.filterwarningssusturur.-W errorile uyarı istisna olurdu ama sunucu işi yapmış olurdu ve yanıt kaybolurdu: bu yüzden çağrı döner ve uyarırewloykaydedicisine (logging) yazılır.
Yanıtın tamamı ve test modu
yanit = rewloy.request(
"sendCampaign",
body={"body": "Bu hafta kahveler 2 damga!"},
idempotency_key="kampanya-2026-10-03",
)
yanit.status # 201
yanit.replayed # True: aynı anahtarın ilk yanıtı yeniden döndü (Idempotent-Replayed)
yanit.request_id # x-request-id
yanit.mode # Rewloy-Mode
yanit.data # kampanya
request(işlem, …) her işlemi çağırır (operationId ya da metot adıyla) ve
yanıtın tamamını döndürür: data, sayfalı listede meta, status,
headers, request_id, mode ve replayed. Adres parametreleri
path={"serial": …} ile verilir. data burada tipli değildir; typing.cast
ya da metodun kendisi.
mode, yanıtın Rewloy-Mode başlığıdır. Platformda test modu hazırlanıyor:
gerçek mesaj göndermeyen, gerçek kart vermeyen test anahtarları. Geldiğinde
test yanıtları bunu bu başlıkla söyleyecek. Başlık yoksa None. Canlı akışta
aynı bilgi akis.modedadır.
İşlem tablosu da dışa açıktır: OPERATIONS["passAction"] →
OperationMeta(id, method_name, http_method, path, auth, merchant, idempotency, body, response, paged, stream, deprecated).
Taşıma ve test etmek
Varsayılan taşıma urllibdir: bağımlılık yok, yönlendirme izlenmez (API
yönlendirmez; izlemek anahtarı başka yere taşıyabilir), yalnız http ve
https, ortam değişkenlerindeki vekil (HTTPS_PROXY) kullanılır. Her istek
yeni bir bağlantı açar. Bağlantı havuzu, HTTP/2 ya da kendi vekil ve sertifika
ayarlarınız için:
import httpx
from rewloy import Rewloy
from rewloy.httpx_transport import HttpxTransport # pip install "rewloy[httpx]"
rewloy = Rewloy(api_key=anahtar, transport=HttpxTransport(httpx.Client(http2=True)))
transport= aynı zamanda sahte bir API'dir: send(request), open_stream(request)
ve close() olan her nesne olur. Kendi kodunuzu ağsız test etmek için:
from rewloy import Headers, HttpRequest, HttpResponse, Rewloy
class SahteTasima:
def send(self, request: HttpRequest) -> HttpResponse:
return HttpResponse(200, "OK", Headers([("Content-Type", "application/json")]),
b'{"data": {"serial": "ABCD-EFGH-JKLM", "balance": 3}}')
def open_stream(self, request: HttpRequest): raise NotImplementedError
def close(self) -> None: pass
rewloy = Rewloy(api_key="rwk_test", transport=SahteTasima())
assert rewloy.get_pass("ABCD-EFGH-JKLM")["balance"] == 3
asyncio
İstemci eşzamanlıdır (decision 18: docs/DECISIONS.md). Bir
asyncio uygulamasında iş parçacığına verin; istemci iş parçacığı güvenlidir:
kart = await asyncio.to_thread(rewloy.get_pass, "ABCD-EFGH-JKLM")
Geliştirme
python3 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
python scripts/generate.py # canlı belgeden: openapi/openapi.json ve src/rewloy/generated/
python scripts/generate.py --file openapi/openapi.json # kayıtlı belgeden
mypy && pytest
src/rewloy/generated/elle düzenlenmez; üreteçscripts/generator.py'dir.- Testler ağa çıkmaz: yerel bir sahte API (
http.server) ile çalışır. - CI her gün canlı belgeyi okur ve bir değişiklik varsa bir pull request açar.
- Kararlar: docs/DECISIONS.md.
Belgeler
| Başlarken | https://rewloy.com/gelistiriciler |
| API referansı | https://rewloy.com/gelistiriciler/api |
| OpenAPI 3.1 | https://app.rewloy.com/v1/openapi.json |
| Hata kodları | https://rewloy.com/gelistiriciler/hatalar |
| API'nin değişiklik günlüğü | https://rewloy.com/gelistiriciler/degisiklikler |
| Bu kütüphanenin değişiklikleri | CHANGELOG.md |
Sürümler:
- Kütüphane anlamsal sürümleme (SemVer) kullanır. 1.0'a kadar arayüzü değişebilir.
- API'ye alan eklemek geriye uyumludur; kütüphanenin tipleri her gün güncellenir.
- Kalkacak bir uç nokta en az 180 gün önce duyurulur ve bu süre boyunca
DeprecationveSunsetbaşlıklarını taşır.
Güvenlik
Bir güvenlik açığı bulursanız SECURITY.md dosyasındaki yoldan özel olarak bildirin. Lütfen herkese açık issue açmayın.
Lisans
English
The official Python library for the Rewloy API.
Status: preview (0.x), published on PyPI. The API is stable; the library's interface may change until 1.0.
The documentation of the API itself is in Turkish (links above). In short:
- Every operation of the API is a method named by its operationId in
snake_case (
passActionispass_action), typed withTypedDicts from the OpenAPI document, which CI reads daily and regenerates from.mypy --strictpasses. - No dependencies: Python 3.9 or later and the standard library (
urllib,json,hmac). An optionalhttpxtransport adds pooling and HTTP/2. - Safe retries,
Idempotency-Keyhandling, pagination, server-sent events, webhook signature verification and deprecation warnings.
Install
Python 3.9 or later:
pip install rewloy
Use
import os
from rewloy import Rewloy
rewloy = Rewloy(api_key=os.environ["REWLOY_API_KEY"]) # or staff_session=…, merchant=… or holder_session=…
created = rewloy.issue_pass(body={"programId": program_id, "email": email, "kvkkConsent": True})
result = rewloy.pass_action(
created["serial"],
body={"action": "earn-stamps", "locationId": location_id},
idempotency_key=f"receipt-{receipt_no}", # generated when omitted, reused across retries
)
- Arguments. Path parameters are positional.
query,body,merchant,idempotency_key,timeout(seconds) andmax_retriesare keywords. The dicts use the API's own key names. - Results. A method returns the answer's
data: aTypedDictor list, aPage(.data,.meta) for paged lists,Nonefor 204,bytesfor files. Types are inrewloy.types(from rewloy.types import IssuePassBody). - The whole answer.
rewloy.request("sendCampaign", body=…)returnsstatus,headers,request_id,mode(theRewloy-Modeheader, for the coming test mode) andreplayed(Idempotent-Replayed) withdata. - Pagination.
rewloy.paginate("listCustomers", query=…)iterates the items of every page, lazily. - Streams.
with rewloy.live_feed() as stream: for event in stream: …iterates server-sent events (event,data,id,json()). It reconnects withLast-Event-IDunlessreconnect=False;close()works from another thread. - Threads and asyncio. The client is thread-safe. It is synchronous:
in async code use
await asyncio.to_thread(rewloy.get_pass, serial). - Testing.
transport=takes anything withsend(),open_stream()andclose(); the README above has a fake.
Webhooks
Verify the raw body (request.get_data() in Flask, await request.body()
in FastAPI, request.body in Django) with the secret shown when the webhook
was created:
event = verify_webhook(raw_body, headers.get("Rewloy-Signature"), secret)
- Check.
Rewloy-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>is compared withhmac.compare_digest, andtmust be within 300 seconds. - Refusal. On failure it raises
WebhookSignatureError: answer 400. - Headers.
Rewloy-Eventis the event type.Rewloy-Deliveryis the same on every retry of a delivery: deduplicate on it. Delivery is at least once.
Errors, retries, deprecations
- Errors. Failures raise
RewloyErrorwithstatus,code(the API's stable code),title,detail,details,request_idandbody. Subclasses:RateLimitError(retry_after),RewloyConnectionErrorandRewloyTimeoutError. Misuse raisesValueErrororTypeError. - What is retried. Network errors, timeouts, 429, 502–504 and
Cloudflare's 520–524, up to
max_retries(default 2), with exponential backoff and jitter, honouringRetry-After. The timeout covers a whole attempt, body included. - Only when safe. Only GET, PUT, DELETE, and POST with an
Idempotency-Key, are retried. - Deprecations. A deprecated operation's answers carry
Deprecation,SunsetandLink. The client issues oneDeprecationWarningper operation, attributed to your calling line. Under-W errorthe call still returns and the notice goes to therewloylogger.
Security and licence
Report vulnerabilities privately, as SECURITY.md says. MIT licensed.
Yeni sürüm yayımlamak / Releasing
src/rewloy/_version.py'deki sürümü ve CHANGELOG'u güncelleyin, commit'leyin, v<sürüm> etiketini gönderin. release.yml PyPI'a güvenilir yayıncı (trusted publishing) yoluyla, jetonsuz yayımlar.
Bump the version in src/rewloy/_version.py and the changelog, commit, and push a v<version> tag. release.yml publishes to PyPI through trusted publishing, with no token.
Metadata
Release files for rewloy 0.1.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 | |
|---|---|---|---|
| rewloy-0.1.0.tar.gz | 358.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rewloy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 495.6 kB
Release files / rewloy-0.1.0.tar.gz
| Download URL | rewloy-0.1.0.tar.gz |
|---|---|
| Size | 358.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
425618a4a371773c0820a30e3ecd76f729a7b8a127b55001d9bdd4fb6e6562e3
|
|
BLAKE2b-256 checksum How to use checksums |
ca1b30a10b592c4bb926bea09c6c52d89a830ad7fd5389d25210e23273fe11e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 4, 2026.
Transparency logRelease files / rewloy-0.1.0-py3-none-any.whl
| Download URL | rewloy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 137.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1779215d70adfa5640f59e770902a648349e1a12e10e342bd2e18bf03b20f2ea
|
|
BLAKE2b-256 checksum How to use checksums |
0659eb8b41768d6787e3a84fb314d2687ef46bdeb4c4dc3b5b74776122c6196b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 4, 2026.
Transparency log