Helpers for driving Cisco TRex nodes through CML console and STL workflows
Project description
trexcmllib
trexcmllib is a small Python library for working with Cisco TRex nodes in CML-style labs.
It has two complementary layers:
TrexConsoleLauncher: open a remote TRex node through a CML terminal server, start the TRex server if needed, and run console CLI batches reliably.TrexCmlLib: a thin wrapper around the bundled TRex STL Python client for simple port, traffic, stats, and ping workflows.TrexAstfConsoleRunner: a console-driven ASTF helper for stateful L3 and application traffic profiles.TrexTraffic: a single high-level class that wrapsTrexConsoleLauncherandTrexAstfConsoleRunnerand powers the bundled traffic examples.
This library was built to solve practical lab tasks:
- bootstrap a TRex console from a CML host
- acquire or observe TRex ports
- configure L2 or L3 port state
- send simple L2 or L3 traffic
- read counters and summarize pass/fail results
- report packet-loss counts and percentages in the bundled examples
- package sample scripts so other tools can reuse them
Status
This repository is structured as an installable Python package and includes:
- package metadata in
pyproject.toml - example console-script entrypoints
- GitHub Actions workflows for linting and publishing
The package is designed for publishing to PyPI, but the runtime workflows still depend on external lab infrastructure such as a reachable CML host and a TRex node.
Installation
Install from a local checkout:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e .
Build local distributions:
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
Dependencies
Python Package Dependencies
- The published package itself has no mandatory third-party PyPI dependencies for the console automation layer.
- The console layer uses the Python standard library plus a local
sshbinary. - The STL layer depends on the TRex client libraries that ship with a
trex-corecheckout.
Local Machine Requirements
Required for console automation:
- Python 3.10+
sshinPATH- network reachability to the CML terminal server
- credentials for the CML host
Required for direct STL API usage through TrexCmlLib:
- everything above, plus access to a
trex-core/scriptsdirectory - if installed outside the repo,
TREX_CORE_SCRIPTS_DIR=/path/to/trex-core/scripts
Remote TRex Node Requirements
Required for TrexConsoleLauncher and the example scripts:
tmuxpython3- TRex installed and reachable using the expected repo-style layout under
/trex - the TRex interactive console modules on the node
Additional requirements for namespace-backed L3 workflows:
stack: linux_basedintrex_cfg.yaml- full
iproute2 - full
sysctlimplementation ethtool
macOS Compatibility Note
TrexCmlLib may not work directly on macOS because some bundled TRex client dependencies are Linux-oriented, especially pyzmq-ctypes. In that case:
- use
TrexConsoleLauncher.run_console_batch(...) - or use the example scripts under
trexcmllib.examples
Package Layout
trexcmllib/
__init__.py
console.py
stl.py
traffic.py
README.md
examples/
__init__.py
common.py
open_console.py
run_l2_traffic.py
run_l2_bidirectional.py
run_l3_traffic.py
run_l3_bidirectional.py
run_ping.py
run_astf_http.py
run_astf_udp.py
Main API
TrexConsoleConfig
Configuration for connecting to a TRex node through a CML terminal server.
Useful fields:
jump_hostuserlab_namenode_namelab_idnode_idnode_portconsole_pathpasswordorpassword_envreadonlyforce_acquire
No real connection target is embedded in the library. Callers are expected to provide the host, user, lab, node, and credentials explicitly.
Console targeting rules:
- provide one lab selector:
lab_nameorlab_id - provide one node selector:
node_nameornode_id - if a name is provided,
trexcmllibresolves the matching id through the CML API before opening the console - or pass
console_pathdirectly if you already know the exact CML terminal path
TrexConsoleLauncher
Primary console automation class.
Useful methods:
connect_and_bootstrap()run_shell_commands(commands)run_console_batch(commands, ports=[...])
run_console_batch is the most reliable option for Mac-hosted automation in this repo because it drives the TRex console CLI on the node itself instead of depending on local TRex client binary compatibility.
TrexCmlLib
Convenience STL wrapper for direct Python API usage.
Useful methods:
connect()acquire_ports()configure_port_attributes()configure_l2_port()configure_l3_port()resolve_ports()set_service_mode()send_l2_traffic()send_l3_traffic()ping()get_stats()clear_stats()stop_traffic()
TrexAstfConsoleRunner
Console-driven ASTF helper for advanced stateful traffic.
Useful methods:
run_profile()build_start_command()build_stats_command()build_stop_command()validate_metrics()
TrexTraffic
Unified console-driven traffic API for the bundled examples.
Useful methods:
run("l2", ...)run("l2_bidirectional", ...)run("l3", ...)run("l3_bidirectional", ...)run("ping", ...)run("astf_http", ...)run("astf_udp", ...)
Each call returns a TrexTrafficResult with:
successsummarymetricsoutputs
The example scripts under trexcmllib.examples are now thin CLI wrappers over TrexTraffic.
Traffic run reset behavior:
TrexTrafficdefaults to a clean-start model for traffic runs- before a traffic run starts, the remote TRex server is restarted into the requested mode so stale state from an aborted or unclean prior run does not leak into the next run
- this applies to the
TrexTraffic-based L2, L3, ping, and ASTF example scripts open_consoleis different: it opens an interactive console without forcing that reset unless you implement that behavior yourself- the example CLIs expose this as
--hard-resetand--no-hard-reset
Important ASTF requirement:
- the remote TRex server must run in ASTF mode, for example
-i --astf - unlike STL, ASTF traffic normally depends on routed client/server profile IP ranges between TRex ports
- ASTF UDP examples report packet loss using
udps_sndpktversusudps_rcvpkt - ASTF TCP examples report data-packet loss using
tcps_sndpackversustcps_rcvpack, plus retransmit and drop counters
Example: Open a Console
from trexcmllib import TrexConsoleConfig, TrexConsoleLauncher
launcher = TrexConsoleLauncher(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
readonly=True,
)
)
launcher.connect_and_bootstrap()
Example: Run a Console Batch
from trexcmllib import TrexConsoleConfig, TrexConsoleLauncher
launcher = TrexConsoleLauncher(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
force_acquire=True,
readonly=False,
)
)
result = launcher.run_console_batch(
[
"service -p 0 1",
"l2 -p 0 --dst 52:54:00:0d:24:82",
"l2 -p 1 --dst 52:54:00:17:0f:5c",
"service --off -p 0 1",
"clear",
"pkt -p 0 -s Ether(src='52:54:00:17:0f:5c',dst='52:54:00:0d:24:82')/IP()/UDP()/('x'*10)",
"stats",
"release -p 0 1",
],
ports=[0, 1],
)
print(result.success)
print(result.output)
Example: Run Traffic Through One API
from trexcmllib import TrexConsoleConfig, TrexTraffic
traffic = TrexTraffic(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
readonly=False,
force_acquire=True,
)
)
# Disable the default clean-start restart only if you explicitly want to reuse
# the current remote TRex server state.
# traffic = TrexTraffic(config, hard_reset=False)
result = traffic.run(
"l2",
packets=10,
tx_port=0,
rx_port=1,
)
print(result.success)
print(result.summary["packet_loss"])
print(result.outputs["traffic"])
Example: Run Unidirectional L3 Traffic
from trexcmllib import TrexConsoleConfig, TrexTraffic
traffic = TrexTraffic(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
readonly=False,
force_acquire=True,
)
)
result = traffic.run(
"l3",
packets=10,
tx_port=0,
tx_src_ip="192.0.2.10",
tx_next_hop="192.0.2.1",
traffic_dst_ip="198.51.100.10",
)
print(result.success)
print(result.summary["resolved_nh_mac"])
print(result.summary["packets_sent"])
print(result.outputs["setup"])
print(result.outputs["traffic"])
Example: Run Ping Validation
from trexcmllib import PingProbe, TrexConsoleConfig, TrexTraffic
traffic = TrexTraffic(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
readonly=False,
force_acquire=True,
)
)
result = traffic.run(
"ping",
count=3,
pkt_size=64,
probes=[
PingProbe(
port=0,
src_ip="192.0.2.10",
next_hop_ip="192.0.2.1",
dst_ip="192.0.2.1",
),
],
)
print(result.success)
print(result.summary["probe_results"][0]["resolved_nh_mac"])
print(result.summary["probe_results"][0]["replies"])
print(result.outputs["port_0"])
Example: Run Bidirectional L3 Traffic
from trexcmllib import TrexConsoleConfig, TrexTraffic
traffic = TrexTraffic(
TrexConsoleConfig(
jump_host="<cml-host>",
user="<ssh-user>",
lab_name="<lab-name>",
node_name="<node-name>",
readonly=False,
force_acquire=True,
)
)
result = traffic.run(
"l3_bidirectional",
packets=10,
port_a=0,
port_b=1,
port_a_src_ip="192.0.2.10",
port_b_src_ip="192.0.2.20",
port_a_next_hop_ip="192.0.2.1",
port_b_next_hop_ip="192.0.2.2",
traffic_a_dst_ip="198.51.100.10",
traffic_b_dst_ip="198.51.100.20",
)
print(result.success)
print(result.summary["loss_a_to_b"])
print(result.summary["loss_b_to_a"])
print(result.outputs["setup"])
print(result.outputs["traffic"])
Example Scripts
These examples can be run as modules when the parent directory of this repository is on PYTHONPATH, or by using the installed console scripts after pip install.
All example scripts support the same CML target selection model:
- one lab selector with
--lab-nameor--lab-id - one node selector with
--node-nameor--node-id - names are resolved to ids through the CML API before the console path is opened
--node-portremains optional and defaults to0
For all examples below:
- you must provide
--cml-hostand--user - you must provide one lab selector and one node selector
- you can provide the SSH secret either with
--passwordor through the password environment variable
Traffic Parameters
Current traffic customization support:
run_l2_trafficandrun_l2_bidirectional- packet mode: supported with
--packets - stream mode: supported with
--rateand--duration - stream frame size: supported with
--frame-size
- packet mode: supported with
run_l3_trafficandrun_l3_bidirectional- packet mode: supported with
--packets - stream mode: supported with
--rateand--duration - packet and stream payload size: supported with
--payload-bytes
- packet mode: supported with
run_ping- ping count: supported with
--count - packet size: supported with
--pkt-size
- ping count: supported with
run_astf_httpandrun_astf_udp- duration: supported with
--duration - traffic rate/load: supported with
--multiplier
- duration: supported with
Stream rate format:
- stream mode accepts TRex rate strings such as
10kpps,100mbps, or5% - L2 and L3 stream mode uses sustained STL streams on the TRex node instead of repeated
pktinjections
Clean-start behavior:
- the traffic example scripts use
TrexTraffic, which restarts the remote TRex server before each run by default - this is intentional so a previously aborted run does not leave stale ports, streams, or server mode behind
- interactive
open_consoleusage does not force that restart by default - use
--no-hard-resetonly when you explicitly want to reuse the current remote TRex server state
Open Console
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.open_console \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name>
Unidirectional L2 Traffic
Mandatory parameters:
--cml-host--user- one lab selector:
--lab-nameor--lab-id - one node selector:
--node-nameor--node-id - either
--packets, or both--rateand--duration
Optional parameters:
--node-port--rate--duration--frame-size--tx-port--rx-port--tx-mac--rx-mac--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l2_traffic \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--packets 10
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l2_traffic \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-id <lab-id> \
--node-id <node-id> \
--rate 10kpps \
--duration 10 \
--frame-size 256
Bidirectional L2 Traffic
Mandatory parameters:
--cml-host--user- one lab selector:
--lab-nameor--lab-id - one node selector:
--node-nameor--node-id - either
--packets, or both--rateand--duration
Optional parameters:
--node-port--rate--duration--frame-size--port-a--port-b--port-a-mac--port-b-mac--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l2_bidirectional \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--packets 10
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l2_bidirectional \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-id <lab-id> \
--node-id <node-id> \
--rate 10kpps \
--duration 10
L3 Traffic
Mandatory parameters:
--cml-host--user- one lab selector:
--lab-nameor--lab-id - one node selector:
--node-nameor--node-id --tx-src-ip--tx-next-hop- either
--packets, or both--rateand--duration
Optional parameters:
--node-port--rate--duration--tx-port--rx-port--rx-src-ip--rx-next-hop--traffic-src-ip--traffic-dst-ip--payload-bytes--udp-src-port--udp-dst-port--tx-mac--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l3_traffic \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--packets 10 \
--tx-port 0 \
--tx-src-ip 192.0.2.10 \
--tx-next-hop 192.0.2.1 \
--traffic-dst-ip 198.51.100.10
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l3_traffic \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-id <lab-id> \
--node-id <node-id> \
--tx-port 0 \
--tx-src-ip 192.0.2.10 \
--tx-next-hop 192.0.2.1 \
--traffic-dst-ip 198.51.100.10 \
--rate 10kpps \
--duration 10
Bidirectional L3 Traffic
Mandatory parameters:
--cml-host--user- one lab selector:
--lab-nameor--lab-id - one node selector:
--node-nameor--node-id --port-a-src-ip--port-b-src-ip--traffic-a-dst-ip--traffic-b-dst-ip- either
--packets, or both--rateand--duration - either both
--port-a-next-hop-ipand--port-b-next-hop-ip - or both
--port-a-next-hop-macand--port-b-next-hop-mac
Optional parameters:
--node-port--rate--duration--port-a--port-b--payload-bytes--udp-src-port--udp-dst-port--port-a-mac--port-b-mac--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l3_bidirectional \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--packets 10 \
--port-a-src-ip 192.0.2.10 \
--port-b-src-ip 192.0.2.20 \
--port-a-next-hop-ip 192.0.2.1 \
--port-b-next-hop-ip 192.0.2.2 \
--traffic-a-dst-ip 198.51.100.10 \
--traffic-b-dst-ip 198.51.100.20
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_l3_bidirectional \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-id <lab-id> \
--node-id <node-id> \
--port-a-src-ip 192.0.2.10 \
--port-b-src-ip 192.0.2.20 \
--port-a-next-hop-ip 192.0.2.1 \
--port-b-next-hop-ip 192.0.2.2 \
--traffic-a-dst-ip 198.51.100.10 \
--traffic-b-dst-ip 198.51.100.20 \
--rate 10kpps \
--duration 10
Ping Validation
Mandatory parameters:
--cml-host--user- one lab selector:
--lab-nameor--lab-id - one node selector:
--node-nameor--node-id - at least one
--probe
Optional parameters:
--node-port--count--pkt-size--show-raw-output--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_ping \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--count 3 \
--probe 0:192.0.2.10:192.0.2.1:192.0.2.1
The --probe format is:
PORT:SRC_IP:NEXT_HOP_IP:DST_IP
Meaning:
PORT: TRex port idSRC_IP: source IP configured on that TRex portNEXT_HOP_IP: gateway / next-hop TRex must ARP-resolve on that portDST_IP: final ICMP destination carried in the ping packet
Examples:
- ping the gateway itself:
--probe 0:192.0.2.10:192.0.2.1:192.0.2.1
- ping a remote host through the gateway:
--probe 0:192.0.2.10:192.0.2.1:198.51.100.10
Important:
- the third field is the next hop, not the final ping destination
- the
l3 -p ... --dst ...command usesNEXT_HOP_IP - the
ping -d ...command usesDST_IP
Default behavior:
- prints per-port ping results
- on failure, prints only the TRex CLI commands that were run for that probe
- hides the full remote bootstrap and console log unless explicitly requested
To include the full raw remote output for debugging:
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_ping \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--count 3 \
--probe 0:192.0.2.10:192.0.2.1:192.0.2.1 \
--show-raw-output
To validate both links, repeat --probe:
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_ping \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--count 3 \
--probe 0:192.0.2.10:192.0.2.1:192.0.2.1 \
--probe 1:198.51.100.10:198.51.100.1:198.51.100.1
ASTF HTTP Application Traffic
Mandatory parameters:
--cml-host--user- either
--lab-nameand--node-name, or--lab-idand--node-id
Optional parameters:
--node-port--profile--profile-id--duration--multiplier--latency-pps--ipv6--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_astf_http \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--duration 10 \
--multiplier 100
ASTF UDP Stateful Traffic
Mandatory parameters:
--cml-host--user- either
--lab-nameand--node-name, or--lab-idand--node-id
Optional parameters:
--node-port--profile--profile-id--duration--multiplier--latency-pps--ipv6--passwordor--password-env
TREXCMLLIB_PASSWORD='<ssh-password>' python3 -m trexcmllib.examples.run_astf_udp \
--cml-host <cml-host> \
--user <ssh-user> \
--lab-name <lab-name> \
--node-name <node-name> \
--duration 10 \
--multiplier 100
Installed Console Scripts
If the package is installed, the same examples are exposed as console scripts:
trexcmllib-open-console
trexcmllib-l2-traffic
trexcmllib-l2-bidirectional
trexcmllib-l3-traffic
trexcmllib-l3-bidirectional
trexcmllib-ping
trexcmllib-astf-http
trexcmllib-astf-udp
Environment Notes
Console Path
The console launcher expects access like:
ssh -tt <ssh-user>@<cml-host> "open /<lab-name>/<node-name>/<node-port>"
Password Handling
Preferred:
export TREXCMLLIB_PASSWORD='your-password'
Or pass password= into TrexConsoleConfig.
Local Host Compatibility
TrexCmlLib uses the bundled TRex STL client from this repo. On macOS, direct STL imports may fail because some bundled dependencies are Linux-oriented. In those cases:
- prefer
TrexConsoleLauncher.run_console_batch(...) - or use the example scripts under
trexcmllib/examples/
If trexcmllib is installed outside the trex-core tree and you want to use TrexCmlLib, point it at the TRex repo scripts directory:
export TREX_CORE_SCRIPTS_DIR=/path/to/trex-core/scripts
TRex Linux-Based Stack
Namespace-backed L3 workflows require:
stack: linux_basedintrex_cfg.yaml- a host image with full
iproute2 - a full
sysctlimplementation ethtool
If those are missing, L2 CLI traffic can still work while namespace/L3 automation fails.
For the run_l3_traffic example specifically:
- the transmit port next hop must answer ARP
- the chosen traffic destination must make sense for your topology
- if you provide an
--rx-port, any receive-side counters depend on an actual return or forwarding path in the lab
For the run_l3_bidirectional example:
- you can use ARP mode with
--port-a-next-hop-ipand--port-b-next-hop-ip - or use explicit MAC mode with
--port-a-next-hop-macand--port-b-next-hop-mac - explicit MAC mode is useful for loopback or lab validation when you want IP traffic counters without depending on ARP
For the run_ping example:
- each
--probeisPORT:SRC_IP:NEXT_HOP_IP:DST_IP - the third field is the gateway / next-hop TRex must resolve on that port
- the fourth field is the final ICMP destination
- the next hop must answer ARP on that specific TRex link
- the destination must answer ICMP through that same path
- if a TRex port is connected only to a local loop or an otherwise empty switch segment, ping validation will fail at L3 resolution because there is no real remote endpoint
- by default, failures show only the CLI commands that were executed; use
--show-raw-outputto print the full remote console session
For the ASTF examples:
- the remote TRex server must be started in ASTF mode, not STL mode
- the client and server IP ranges embedded in the ASTF profile must be routable between the participating TRex ports
run_astf_http.pydefaults toastf/http_simple.pyrun_astf_udp.pydefaults toastf/udp_pcap.py- these examples validate stateful counters such as
tcps_connectsorudps_connectsand byte symmetry between client and server
Publishing
This repository includes a GitHub Actions workflow for PyPI Trusted Publishing.
Recommended flow:
- Create the project on PyPI and TestPyPI.
- Configure Trusted Publishers on both indexes for this GitHub repository and workflow file.
- Run the workflow manually to publish to TestPyPI.
- Verify installation from TestPyPI.
- Create a GitHub release to publish to PyPI.
Manual build and upload remains available if you prefer twine:
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
python -m twine upload --repository testpypi dist/*
python -m twine upload dist/*
Recommended Next Steps
- add automated tests for output parsing and batch success detection
- add CI for
py_compile, packaging, and example--helpsmoke tests - decide whether the top-level repo scripts should remain wrappers or move entirely under the package
- document the supported TRex server images and required node-side tools more formally
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trexcmllib-0.1.2.tar.gz.
File metadata
- Download URL: trexcmllib-0.1.2.tar.gz
- Upload date:
- Size: 47.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50f134277ab423ab9962a08b983073338530113a86b0c5379cab86936cdb4929
|
|
| MD5 |
a1c94590a1c2d071f671d4d6668498b7
|
|
| BLAKE2b-256 |
9a41a4d5753ab875a391e3661cbc7fafd2dea096d83a3709c7ac760acb2f1cc3
|
File details
Details for the file trexcmllib-0.1.2-py3-none-any.whl.
File metadata
- Download URL: trexcmllib-0.1.2-py3-none-any.whl
- Upload date:
- Size: 53.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbc3e915a3f07decdb52b878242038173edbbd94a01b4aface73294ef78b24de
|
|
| MD5 |
9eebb06f04d765d9957a14f063cba289
|
|
| BLAKE2b-256 |
2aef21316ce8c5767946018fc5b7bb0a4f0bd657cdad71f6ab00d8fe7fcba61d
|