Skip to main content

slick-queue-py

Python implementation of SlickQueue - a lock-free multi-producer multi-consumer (MPMC) queue with C++ interoperability through shared memory.

This is the Python binding for the SlickQueue C++ library. The Python implementation maintains exact binary compatibility with the C++ version, enabling seamless interprocess communication between Python and C++ applications.

License: MIT CI GitHub release

Features

  • Dual Mode Operation:
    • Local Memory Mode: In-process queue using local memory (no shared memory overhead)
    • Shared Memory Mode: Inter-process queue for interprocess communication
  • Lock-Free Multi-Producer Multi-Consumer: True MPMC support using atomic operations
  • C++/Python Interoperability: Python and C++ processes can share the same queue
  • Cross-Platform: Windows and Linux/macOS support (x86-64)
  • Memory Layout Compatible: Exact binary compatibility with C++ slick::SlickQueue<T>
  • High Performance: Hardware atomic operations for minimal overhead

Requirements

  • Python 3.8+ (uses multiprocessing.shared_memory)
  • 64-bit platform
  • For true lock-free operation: x86-64 CPU with CMPXCHG16B support (most CPUs since 2006)

Installation

pip install -e .

Or just copy the Python files to your project.

Quick Start

Local Memory Mode (Single Process)

from slick_queue_py import SlickQueue

# Create a queue in local memory (no shared memory)
q = SlickQueue(size=1024, element_size=256)

# Producer: Reserve a slot, write data, and publish
idx = q.reserve()
buf = q[idx]
buf[:len(b'hello')] = b'hello'
q.publish(idx)

# Consumer: Read data
read_index = 0
data, size, read_index = q.read(read_index)
if data is not None:
    print(f"Received: {data[:size]}")

q.close()  # unlink() does nothing for local mode

Shared Memory Mode (Multi-Process)

from slick_queue_py import SlickQueue

# Create a new shared memory queue (size must be power of two)
q = SlickQueue(name='my_queue', size=1024, element_size=256)

# Producer: Reserve a slot, write data, and publish
idx = q.reserve()
buf = q[idx]
buf[:len(b'hello')] = b'hello'
q.publish(idx)

# Consumer: Read data
read_index = 0
data, size, read_index = q.read(read_index)
if data is not None:
    print(f"Received: {data[:size]}")

q.close()
q.unlink()  # Delete shared memory segment

Multi-Producer Usage

from multiprocessing import Process
from slick_queue_py import SlickQueue
import struct

def producer_worker(queue_name, worker_id, num_items):
    # Open existing queue
    q = SlickQueue(name=queue_name, element_size=32)

    for i in range(num_items):
        # Reserve slot (thread-safe with atomic CAS)
        idx = q.reserve(1)

        # Write unique data
        data = struct.pack("<I I", worker_id, i)
        slot = q[idx]
        slot[:len(data)] = data

        # Publish (makes data visible to consumers)
        q.publish(idx, 1)

    q.close()

# Create queue
q = SlickQueue(name='mpmc_queue', size=64, element_size=32)

# Start multiple producers
producers = []
for i in range(4):
    p = Process(target=producer_worker, args=('mpmc_queue', i, 100))
    p.start()
    producers.append(p)

# Wait for completion
for p in producers:
    p.join()

q.close()
q.unlink()

Multi-Consumer Work-Stealing

For multiple consumers sharing work from a single queue, use an AtomicCursor to enable work-stealing patterns where each item is consumed by exactly one consumer.

Local Mode (Multi-Threading)

from threading import Thread
from slick_queue_py import SlickQueue, AtomicCursor
import struct

def consumer_worker(q, cursor, worker_id, results):
    items_processed = 0
    while True:
        # Atomically claim next item (work-stealing)
        data, size, index = q.read(cursor)

        if data is None:
            break  # No more data

        # Process the claimed item
        worker, seq = struct.unpack("<I I", data[:8])
        items_processed += 1

    results[worker_id] = items_processed

# Create local queue and cursor
q = SlickQueue(size=64, element_size=32)
cursor_buf = bytearray(8)
cursor = AtomicCursor(cursor_buf, 0)
cursor.store(0)  # Initialize cursor to 0

# Producer writes items
for i in range(100):
    idx = q.reserve()
    data = struct.pack("<I I", 0, i)
    q[idx][:len(data)] = data
    q.publish(idx)

# Start multiple consumer threads that share the work
results = {}
threads = []
for i in range(4):
    t = Thread(target=consumer_worker, args=(q, cursor, i, results))
    t.start()
    threads.append(t)

# Wait for all consumers
for t in threads:
    t.join()

print(f"Total items processed: {sum(results.values())}")
q.close()

Shared Memory Mode (Multi-Process)

from multiprocessing import Process, shared_memory
from slick_queue_py import SlickQueue, AtomicCursor
import struct

def consumer_worker(queue_name, cursor_name, worker_id):
    # Open shared queue and cursor
    q = SlickQueue(name=queue_name, element_size=32)
    cursor_shm = shared_memory.SharedMemory(name=cursor_name)
    cursor = AtomicCursor(cursor_shm.buf, 0)

    items_processed = 0
    while True:
        # Atomically claim next item (work-stealing)
        data, size, index = q.read(cursor)

        if data is None:
            break  # No more data

        # Process the claimed item
        worker, seq = struct.unpack("<I I", data[:8])
        items_processed += 1

    print(f"Worker {worker_id} processed {items_processed} items")
    cursor_shm.close()
    q.close()

# Create queue and shared cursor
q = SlickQueue(name='work_queue', size=64, element_size=32)
cursor_shm = shared_memory.SharedMemory(name='work_cursor', create=True, size=8)
cursor = AtomicCursor(cursor_shm.buf, 0)
cursor.store(0)  # Initialize cursor to 0

# Producer writes items
for i in range(100):
    idx = q.reserve()
    data = struct.pack("<I I", 0, i)
    q[idx][:len(data)] = data
    q.publish(idx)

# Start multiple consumer processes that share the work
consumers = []
for i in range(4):
    p = Process(target=consumer_worker, args=('work_queue', 'work_cursor', i))
    p.start()
    consumers.append(p)

# Wait for all consumers
for p in consumers:
    p.join()

cursor_shm.close()
cursor_shm.unlink()
q.close()
q.unlink()

C++/Python Interoperability

The Python implementation is fully compatible with the C++ SlickQueue library. Python and C++ processes can produce and consume from the same queue with:

  • Exact memory layout compatibility: Binary-compatible with slick::SlickQueue<T>
  • Atomic operation compatibility: Same 16-byte and 8-byte CAS semantics
  • Bidirectional communication: C++ ↔ Python in both directions
  • Multi-producer support: Mix C++ and Python producers on the same queue

Platform Support for C++/Python Interop:

  • Linux/macOS: Full interoperability (both use POSIX shm_open)
  • Windows: Full interoperability
  • Python-only: Works on all platforms (Windows/Linux/macOS)

Basic C++ → Python Example

C++ Producer:

#include "queue.h"

int main() {
    // Open existing queue created by Python
    slick::SlickQueue<uint8_t> q(32, "shared_queue");

    for (int i = 0; i < 100; i++) {
        auto idx = q.reserve();
        uint32_t value = i;
        std::memcpy(q[idx], &value, sizeof(value));
        q.publish(idx);
    }
}

Python Consumer:

from slick_queue_py import SlickQueue
import struct

# Create queue that C++ will write to
q = SlickQueue(name='shared_queue', size=64, element_size=32)

read_index = 0
for _ in range(100):
    data, size, read_index = q.read(read_index)
    if data is not None:
        value = struct.unpack("<I", data[:4])[0]
        print(f"Received from C++: {value}")

q.close()
q.unlink()

Building C++ Programs

To use the C++ SlickQueue library with your Python queues:

# Clone the C++ library
git clone https://github.com/SlickQuant/slick-queue.git

# Build your C++ program
g++ -std=c++17 -I slick-queue/include my_program.cpp -o my_program

Or use CMake (see CMakeLists.txt for reference):

include(FetchContent)
FetchContent_Declare(
    slick-queue
    GIT_REPOSITORY https://github.com/SlickQuant/slick-queue.git
    GIT_TAG main
)
FetchContent_MakeAvailable(slick-queue)

add_executable(my_program my_program.cpp)
target_link_libraries(my_program PRIVATE slick::queue)

See tests/test_interop.py and tests/cpp_*.cpp for comprehensive examples.

API Reference

SlickQueue

__init__(*, name=None, size=None, element_size=None)

Create a queue in local memory or shared memory mode.

Parameters:

  • name (str, optional): Shared memory segment name. If None, uses local memory mode (single process).
  • size (int): Queue capacity (must be power of 2). Required for local mode or when creating shared memory.
  • element_size (int, required): Size of each element in bytes

Examples:

# Local memory mode (single process)
q = SlickQueue(size=256, element_size=64)

# Create new shared memory queue
q = SlickQueue(name='my_queue', size=256, element_size=64)

# Open existing shared memory queue
q2 = SlickQueue(name='my_queue', element_size=64)

reserve(n=1) -> int

Reserve n elements for writing. Multi-producer safe using atomic CAS.

Parameters:

  • n (int): Number of elements to reserve (default 1)

Returns:

  • int: Starting index of reserved space

Example:

idx = q.reserve(1)  # Reserve 1 elements

publish(index, n=1)

Publish data written to reserved space. Uses atomic operations with release memory ordering.

Parameters:

  • index (int): Index returned by reserve()
  • n (int): Number of elements to publish (default 1)

Example:

idx = q.reserve()
q[idx][:data_len] = data
q.publish(idx)

read(read_index) -> Tuple[Optional[bytes], int, int] or read(atomic_cursor) -> Tuple[Optional[bytes], int]

Read from queue with two modes:

Single-Consumer Mode (when read_index is int): Uses a plain int cursor for single-consumer scenarios. Returns the new read_index.

Multi-Consumer Mode (when read_index is AtomicCursor): Uses an atomic cursor for work-stealing/load-balancing across multiple consumers. Each consumer atomically claims items, ensuring each item is consumed exactly once.

Parameters:

  • read_index (int or AtomicCursor): Current read position or shared atomic cursor

Returns:

  • Single-consumer: Tuple[Optional[bytes], int, int] - (data or None, size, new_read_index)
  • Multi-consumer: Tuple[Optional[bytes], int] - (data or None, size)

API Difference from C++: Unlike C++ where read_index is updated by reference, the Python single-consumer version returns the new index. This is the Pythonic pattern since Python doesn't have true pass-by-reference.

# Python single-consumer (returns new index)
data, size, read_index = q.read(read_index)

# Python multi-consumer (atomic cursor)
from slick_queue_py import AtomicCursor
cursor = AtomicCursor(cursor_shm.buf, 0)
data, size, index = q.read(cursor)  # Atomically claim next item

# C++ (updates by reference for both)
auto [data, size] = queue.read(read_index);  // read_index modified in-place
auto [data, size] = queue.read(atomic_cursor);  // atomic_cursor modified in-place

Single-Consumer Example:

read_index = 0
while True:
    data, size, read_index = q.read(read_index)
    if data is not None:
        process(data)

Multi-Consumer Example (Local Mode - Threading):

from slick_queue_py import AtomicCursor

# Create local cursor for multi-threading
cursor_buf = bytearray(8)
cursor = AtomicCursor(cursor_buf, 0)
cursor.store(0)

# Multiple threads can share this cursor
while True:
    data, size, index = q.read(cursor)  # Each thread atomically claims items
    if data is not None:
        process(data)

Multi-Consumer Example (Shared Memory Mode - Multiprocess):

from multiprocessing import shared_memory
from slick_queue_py import AtomicCursor

# Create shared cursor for multi-process
cursor_shm = shared_memory.SharedMemory(name='cursor', create=True, size=8)
cursor = AtomicCursor(cursor_shm.buf, 0)
cursor.store(0)

# Multiple processes can share this cursor
while True:
    data, size, index = q.read(cursor)  # Each process atomically claims items
    if data is not None:
        process(data)

read_last() -> Tuple[Optional[bytes], int]

Read the most recently published item.

Returns:

  • Tuple[Optional[bytes], int]: Tuple of (data, size)
    • data: Last published data or None if queue is empty
    • size: Number of slots the item occupies (0 if queue is empty)

Example:

data, size = q.read_last()
if data is not None:
    print(f"Last item: {data[:size * element_size]}")

__getitem__(index) -> memoryview

Get memoryview for writing to reserved slot.

Parameters:

  • index (int): Index from reserve()

Returns:

  • memoryview: View into the data array

close()

Close the shared memory connection. Always call this before unlinking.

unlink()

Delete the shared memory segment. Only call from the process that created it.

AtomicCursor

The AtomicCursor class enables multi-consumer work-stealing patterns by providing an atomic read cursor that multiple consumers can coordinate through. Works in both local mode (multi-threading) and shared memory mode (multi-process).

__init__(buffer, offset=0)

Create an atomic cursor wrapper around a memory buffer.

Parameters:

  • buffer (memoryview or bytearray): Memory buffer
    • For local mode (threading): use bytearray(8)
    • For shared memory mode (multiprocess): use SharedMemory.buf
  • offset (int, optional): Byte offset in buffer (default 0)

Local Mode Example (Multi-Threading):

from slick_queue_py import AtomicCursor

# Create local cursor for multi-threading
cursor_buf = bytearray(8)
cursor = AtomicCursor(cursor_buf, 0)
cursor.store(0)  # Initialize to 0

Shared Memory Mode Example (Multi-Process):

from multiprocessing import shared_memory
from slick_queue_py import AtomicCursor

# Create shared cursor for multi-process
cursor_shm = shared_memory.SharedMemory(name='cursor', create=True, size=8)
cursor = AtomicCursor(cursor_shm.buf, 0)
cursor.store(0)  # Initialize to 0

load() -> int

Load the cursor value with atomic acquire semantics.

Returns:

  • int: Current cursor value

store(value)

Store a new cursor value with atomic release semantics.

Parameters:

  • value (int): New cursor value

compare_exchange_weak(expected, desired) -> Tuple[bool, int]

Atomically compare and swap the cursor value.

Parameters:

  • expected (int): Expected cursor value
  • desired (int): Desired cursor value

Returns:

  • Tuple[bool, int]: (success, actual_value)

Note: This is used internally by read(atomic_cursor) and typically doesn't need to be called directly.

Memory Layout

The queue uses the same memory layout as C++ slick::SlickQueue<T>:

Offset | Size          | Content
-------|---------------|------------------
0      | 16 bytes      | reserved_info (atomic)
       |   0-7         |   uint64_t index_
       |   8-11        |   uint32_t size_
       |   12-15       |   padding
16     | 4 bytes       | uint32_t size_ (queue capacity)
20     | 44 bytes      | padding (to 64 bytes)
64     | 16*size bytes | slot array
       | per slot:     |
       |   0-7         |   uint64_t data_index (atomic)
       |   8-11        |   uint32_t size
       |   12-15       |   padding
64+... | elem*size     | data array

Platform Support

Fully Supported (Lock-Free)

  • Windows x86-64: Uses C++ extension (atomic_ops_ext.pyd) with std::atomic
  • Linux x86-64: Uses C++ extension (atomic_ops_ext.so) with std::atomic, fallback to libatomic
  • macOS x86-64: Uses C++ extension (atomic_ops_ext.so) with std::atomic, fallback to compiler builtins

Platform-specific atomic operation implementations:

  • All platforms: The atomic_ops_ext C++ extension is now used on all platforms for the most reliable cross-process atomic operations
  • Fallback support: Linux/macOS can fall back to libatomic or compiler builtins if the extension isn't available

Building and Installation

The C++ extension is built automatically during installation:

# Install with automatic extension build
pip install -e .

# Or build manually first
python setup.py build_ext --inplace
pip install -e .

Build requirements:

  • Windows: Visual Studio 2017+ or MSVC build tools
  • Linux: GCC 5+ or Clang 3.8+
  • macOS: Xcode command line tools (clang)
  • All platforms: Python development headers (included with standard Python installation)

The extension will be built as:

  • Windows: atomic_ops_ext.cp3XX-win_amd64.pyd
  • Linux: atomic_ops_ext.cpython-3XX-x86_64-linux-gnu.so
  • macOS: atomic_ops_ext.cpython-3XX-darwin.so

(where XX is your Python version, e.g., 312 for Python 3.12)

Requirements for Lock-Free Operation

All platforms require hardware support for lock-free atomic operations:

  • x86-64 CPU with CMPXCHG16B instruction (Intel since ~2006, AMD since ~2007)
  • For C++/Python interoperability, both must use the same atomic hardware instructions
  • No fallback implementation exists - lock-free atomics are mandatory for multi-producer queues

Why no fallback? The queue requires true atomic CAS operations for correctness in multi-producer scenarios. A lock-based fallback would:

  • Break binary compatibility with C++ SlickQueue
  • Fail to work correctly in multi-process scenarios (Python ↔ C++)
  • Not provide the performance guarantees of a lock-free queue

Not Supported

  • 32-bit platforms (no 16-byte atomic CAS)
  • ARM64 (requires ARMv8.1+ CASP instruction - future support planned)
  • CPUs without CMPXCHG16B support (very old x86-64 CPUs from before 2006)

Check platform support:

from atomic_ops import check_platform_support

supported, message = check_platform_support()
print(f"Platform: {message}")

Performance

Typical throughput on modern hardware (x86-64):

  • Single producer/consumer: ~5-10M items/sec
  • 4 producers/1 consumer: ~3-8M items/sec
  • High contention (8+ producers): ~1-5M items/sec

Performance depends on:

  • CPU cache topology
  • Queue size (smaller = more contention)
  • Item size
  • Memory bandwidth

Advanced Usage

Batch Operations

Reserve and publish multiple elements at once:

# Reserve 10 elements
idx = q.reserve(10)

# Write data to each slot
for i in range(10):
    element = q[idx + i]
    element[:data_len] = data[i]

# Publish all 10 elements at once
q.publish(idx, 10)

Wrap-Around Handling

The queue automatically handles ring buffer wrap-around:

# Queue with size=8
q = SlickQueue(name='wrap_test', size=8, element_size=32)

# Reserve more items than queue size - wraps automatically
for i in range(100):
    idx = q.reserve()
    q[idx][:4] = struct.pack("<I", i)
    q.publish(idx)

Testing

Python Tests

Run the Python test suite:

# Atomic operations tests (clean output)
python tests/run_test.py tests/test_atomic_ops.py

# Basic queue tests (clean output)
python tests/run_test.py tests/test_queue.py

# Local mode tests
python tests/test_local_mode.py

# Multi-producer/consumer tests
# Note: If tests fail with "File exists" errors, run cleanup first:
python tests/cleanup_shm.py
python tests/test_multi_producer.py

C++/Python Interoperability Tests

Build and run comprehensive interop tests:

# 1. Build C++ test programs with CMake
mkdir build && cd build
cmake ..
cmake --build .

# 2. Run interoperability test suite
cd ..
python tests/test_interop.py

# Or run specific tests:
python tests/test_interop.py --test python_producer_cpp_consumer
python tests/test_interop.py --test cpp_producer_python_consumer
python tests/test_interop.py --test multi_producer_interop
python tests/test_interop.py --test stress_interop
python tests/test_interop.py --test cpp_shm_creation

The interop tests verify:

  • Python → C++: Python producers write data that C++ consumers read
  • C++ → Python: C++ producers write data that Python consumers read
  • Mixed Multi-Producer: Multiple C++ and Python producers writing to same queue
  • Stress Test: High-volume bidirectional communication
  • SHM created by C++: C++ producers create the SHM and write data that Python consumers read

Note on Windows: If child processes from previous test runs don't terminate properly, you may need to manually kill orphaned python.exe processes before running tests again.

Known Issues

  1. Buffer Cleanup Warning: You may see a BufferError: cannot close exported pointers exist warning during garbage collection. This is a harmless warning caused by Python's ctypes creating internal buffer references that persist beyond explicit cleanup. It occurs during program exit and does not affect functionality, performance, or correctness. The queue works perfectly despite this warning.

  2. UserWarning: On Linux you may see UserWarning: resource_tracker: There appear to be 4 leaked shared_memory objects to clean up at shutdown. This is a harmless warning caused by Python's ctypes creating internal buffer references that persist beyond explicit cleanup. It occurs during program exit and does not affect functionality, performance, or correctness. The queue works perfectly despite this warning.

Architecture

Atomic Operations

The queue uses platform-specific atomic operations:

  • 8-byte CAS: For reserved_info structure (multi-producer coordination)
  • 8-byte CAS: For slot data_index fields (publish/read synchronization)
  • Memory barriers: Acquire/release semantics for proper ordering

Memory Ordering

  • reserve(): Uses memory_order_release on successful CAS
  • publish(): Uses memory_order_release for data_index store
  • read(): Uses memory_order_acquire for data_index load

This ensures:

  • All writes to data are visible before publishing
  • All reads of data happen after acquiring the index
  • No reordering that could cause data races

Comparison with C++

Feature C++ Python
Multi-producer
Multi-consumer (work-stealing) ✅ (with AtomicCursor)
Lock-free (x86-64)
Memory layout Reference Matches exactly
Performance Baseline ~50-80% of C++
Ease of use Medium High
read(int) single-consumer
read(atomic cursor) multi-consumer

Contributing

Issues and pull requests welcome at SlickQuant/slick-queue-py.

License

MIT License - see LICENSE file for details.

Made with ⚡ by SlickQuant

Download files

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

Source Distribution

slick_queue_py-1.2.0.tar.gz (64.9 kB view details)

Uploaded Source

Built Distributions

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

slick_queue_py-1.2.0-cp313-cp313-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.13Windows x86-64

slick_queue_py-1.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp313-cp313-macosx_10_13_universal2.whl (26.9 kB view details)

Uploaded CPython 3.13macOS 10.13+ universal2 (ARM64, x86-64)

slick_queue_py-1.2.0-cp312-cp312-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.12Windows x86-64

slick_queue_py-1.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.4 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp312-cp312-macosx_10_13_universal2.whl (26.9 kB view details)

Uploaded CPython 3.12macOS 10.13+ universal2 (ARM64, x86-64)

slick_queue_py-1.2.0-cp311-cp311-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.11Windows x86-64

slick_queue_py-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp311-cp311-macosx_10_9_universal2.whl (27.0 kB view details)

Uploaded CPython 3.11macOS 10.9+ universal2 (ARM64, x86-64)

slick_queue_py-1.2.0-cp310-cp310-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.10Windows x86-64

slick_queue_py-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.4 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp310-cp310-macosx_10_9_universal2.whl (27.0 kB view details)

Uploaded CPython 3.10macOS 10.9+ universal2 (ARM64, x86-64)

slick_queue_py-1.2.0-cp39-cp39-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.9Windows x86-64

slick_queue_py-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp39-cp39-macosx_10_9_universal2.whl (27.0 kB view details)

Uploaded CPython 3.9macOS 10.9+ universal2 (ARM64, x86-64)

slick_queue_py-1.2.0-cp38-cp38-win_amd64.whl (28.0 kB view details)

Uploaded CPython 3.8Windows x86-64

slick_queue_py-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (40.6 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

slick_queue_py-1.2.0-cp38-cp38-macosx_10_9_universal2.whl (26.8 kB view details)

Uploaded CPython 3.8macOS 10.9+ universal2 (ARM64, x86-64)

File details

Details for the file slick_queue_py-1.2.0.tar.gz.

File metadata

  • Download URL: slick_queue_py-1.2.0.tar.gz
  • Upload date:
  • Size: 64.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for slick_queue_py-1.2.0.tar.gz
Algorithm Hash digest
SHA256 cb47f9127ea25dbaa26dd2337d6abf6f7d293004821588c9345eb54ecda6b4cd
MD5 565edd67e3c9a52ae41e3819e62ece97
BLAKE2b-256 e548d2af32f17e0352d37d8ab55bb75d69228145529f0f6cf62196d519ac91ca

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 ae597b6f86758b364abd6796f1920dbcaab9a2dd11f55ac50d1493803469ab72
MD5 ed24766fbb6d880f8fe74514c7eda88b
BLAKE2b-256 1db9bf990eb009e3eea29a1792626ede21a93d718db692658a1f1c4d11c1f7f6

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 902cad4fd383c8fc9eaba0a00a95a436484c33e6ac4cae5988e230745ef44319
MD5 63c21c0455644c2f32c53caa3818a39a
BLAKE2b-256 dc4a65e4ed8d80f7dc2dc9ed8a95f46e38f6f6e1f6e09a68bb06d68c699ce94a

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp313-cp313-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp313-cp313-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 9caff24a643868974aad53a29dd2d8b324933691a7d46b81787ea449cef1d3dd
MD5 a6d05976185ae33e108dcc19354353e9
BLAKE2b-256 587135f7883c238c0bcb6e9b1d6152df8ff133059b41cf4cc585708e5c200e9e

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 0f0a40e9764e6fdfbc453c8548b130a7e1084d9559533afbf956e566bff319ae
MD5 e208832dcae7fa64b63105a9f64010f6
BLAKE2b-256 a95454c9e035e9a91e52cdd24dec4616101ab8631498127976b90ab4f39379d6

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 52caed9b326403d9f8394f90b023c9de2c377b3ef49acdd4ec7c5c06cc6a36b6
MD5 f6c05d12db5f2f272563fcc4b3d5cef6
BLAKE2b-256 09eb54ec9cc8502e7a6388d3c023ac9058713e83322c5bf2a3d937d1d6483196

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 bbc04d624a67e23e168970352cf438144e47f1a217b9b78583e07a27e5948d46
MD5 4eaea3c211869b11a4c0ce864ce6f49b
BLAKE2b-256 1c0700019fab9c6bf96ee3932c5d85e8a905b6c6857d1adf7802cfccc76d2cf0

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 a78a9631a8d529ebd8df4095a575f3314c1b35cef92ab91d69d26016ba8cbeb1
MD5 26be1e4029028e5eadce5916b4ba41da
BLAKE2b-256 ef9a37ed4a14663291011607127e16b6442a4be20948227e648f66a54d16cd29

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4357cc13270653f8ffd2d173b3f0c1fc509468c513259715eac4fe20bef74ec8
MD5 f0bf09e05e480fbb60065f47b66a1361
BLAKE2b-256 99ea93f2d300a6bd9c9269991d46681e226269c1caf4f98bca9f0d09e9791d3a

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 bb35bdf1702d6c82a934d88fc9d17a11731e85e8cf94f505af682484ddfcb0db
MD5 1e8689354aadb7b129d5a31bafebd2bb
BLAKE2b-256 7d86615858b93123e81908d5f967b0c3071e0e4d0f480decd4651d8fc131ba7a

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 9e2fb4837a4e6d392bf11814d52b4df4ba4a1e2e313e141eb3bdc452ea490780
MD5 84a6ed1be4e667d49cf51a311248e602
BLAKE2b-256 8a3cdc44041ea9cdea2eb01dc93592949ddd90985d9215076c7f129562072a9c

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 68ed2ff0a64cf6ec09abc4f170a29b3e65bedb6a520513e9026b6aa5a8e6ca88
MD5 c3db4075345b9741678acc8378b3c85a
BLAKE2b-256 b32f939f291e5093db8c5b0ae73bc12af5fb3046f40fa5d0443edd581e7fa0ab

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp310-cp310-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 75b58b145fd6b3d4c983e58780b5efbe07314280c2101a7ac3929dce855868af
MD5 fd118620081271ab33a6f8f073f14727
BLAKE2b-256 e9d1143f1e787f2839a219a98a067a5e14c0acf82f2325ecb579ef7b071377cf

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 c14fc01de9c3e1deab0708aebd7969c5a574e7c1cb23ec836da1dceef7efdcfa
MD5 e9aacaa10bca3434b0efc4508675f349
BLAKE2b-256 03ae21a3c4e917eb254ed3c4a7f7b8a22a005d00717621f00a6b52d2ab1d13f5

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1487dea1d278824bf533b62719e40a87309295518fa5c8266605b65c8f1e3b80
MD5 d7124d9ee9774dee07ed35da5df00933
BLAKE2b-256 102a0fae5668b8a272216fb30f1e407de92b13228494c324e304d4964a026068

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp39-cp39-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp39-cp39-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 c40aa91078b7898f9b394043a3433fd900e0dc3e5912be4b22441429e9fc5113
MD5 d60ec6bae8f443c6f31719406498d07f
BLAKE2b-256 fcce468a994628038a83a8c3ddb53b60972d0576ba5db4669a09749912c1f9b0

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp38-cp38-win_amd64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 7cf5427dceb078b6f83d4e67d22d55298d23b63d14ce9d277a012cefb283c7a0
MD5 8b899e1cc89d0ca874792430fba6b6c1
BLAKE2b-256 4418da6a2e731df3c11b93ecb6e3ad7a3920e6045e44f8fa97a2f670d8cdee76

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 72d0b3c0514228101f0584a17092b47601baed959daeb5a1d3da71d673de5433
MD5 504ea451b942372b38719d3cbc91041a
BLAKE2b-256 e588f4a76cd2f29552bcbdbe7071d81d4d806c95095d743e5aa15a2fc52b7f16

See more details on using hashes here.

File details

Details for the file slick_queue_py-1.2.0-cp38-cp38-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for slick_queue_py-1.2.0-cp38-cp38-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 582758a2e38c23972c31a9b2696b70d47c7260cc8c1d7228c377bd55851809c4
MD5 899470e2f8508ee89dbb25d91f25edb1
BLAKE2b-256 ccac8fe054dd676a394734f1c568e57f5a8d3b857bb97d4380b7023463e76c0b

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.2.0 This release

19 files

1.1.0

19 files

1.0.0

2 files

Supported by

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