Skip to main content

A collection of helpful tools

Project description

Active Development CI Test Status License: LGPL-2.1 PyPI Downloads coverage

aplustools2

aplustools2 is a simple, user-friendly Python library for performing amazing tasks. It simplifies complex processes, allowing you to achieve more with less code. Developed with a focus on ease of use and efficiency, aplustools is the go-to solution for Python developers looking to enhance their projects.

Compatibility

๐ŸŸฉ (Works perfectly); ๐ŸŸจ (Untested); ๐ŸŸง (Some Issues); ๐ŸŸฅ (Unusable)

OS UX & README instructions Tests More Complex Functionalities
Windows ๐ŸŸฉ ๐ŸŸฉ ๐ŸŸฉ
MacOS ๐ŸŸจ ๐ŸŸฉ ๐ŸŸจ
Linux (Ubuntu 22.04 LTS) ๐ŸŸฉ ๐ŸŸฉ ๐ŸŸจ

Features

  • Easy to use for beginners, but not lacking for experts
  • Pretty efficient
  • Supports the three main platforms
  • Regular updates and support
  • Comprehensive documentation

Installation

You can install aplustools2 via pip:

pip install aplustools[all] --pre --upgrade

Or clone the repository and install manually:

git clone https://github.com/Adalfarus/aplustools.git
cd aplustools
python -m build

(If you have problems with the package please use py -m pip install aplustools[all] --pre --upgrade --user) (The standard shortform for aplustools is aps, so please use import aplustools as aps for consistency)

๐Ÿ“ฆ Usage

Here are a few quick examples of how to use aplustools.


๐Ÿ” auto_repr: Auto-generate clean __repr__

from aplustools.io.env import auto_repr

@auto_repr
class Person:
    def __init__(self, name: str, age: int, email: str):
        self.name = name
        self.age = age
        self.email = email
        self._internal = "should be hidden"

p = Person("Alice", 30, "alice@example.com")
print(p)  # Person(name=Alice, age=30, email=alice@example.com)

๐Ÿ” auto_repr_with_privates: Show private fields too

from aplustools.io.env import auto_repr_with_privates

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self._age = age  # Will be shown in __repr__

auto_repr_with_privates(Person, use_repr=True)
print(Person("Bob", 42))  # Person(name='Bob', _age=42)

๐Ÿ” File Locking (Cross-Platform)

โœ… Manual file locking via get_system()

from aplustools.io.env import get_system

fd = get_system().lock_file("test.lock", blocking=True)
print(get_system().is_file_locked("test.lock"))  # True
get_system().unlock_file(fd)

โœ… Context-managed locking via OSFileLock

from aplustools.io.fileio import OSFileLock

with OSFileLock("test.lock") as fd:
    print(f"Locked with fd={fd}")
# Lock is automatically released here

โœ… Pythonic locking with os_open (like open())

from aplustools.io.fileio import os_open

with os_open("example.txt", "w") as file:
    file.write("Hello, safely locked world!\n")

Internally uses OSFileLock for safe, exclusive access across platforms (Unix/Windows).


๐Ÿ”ข Binary Encoding Utilities (aplustools.data.bintools)

Efficient tools for working with binary formats and structured bytes.


๐Ÿ“ Measure bit and byte length

from aplustools.data.bintools import bit_length, bytes_length

print(bit_length(42))      # 6
print(bytes_length(1000))  # 2

๐Ÿ” Encode/Decode integers

from aplustools.data.bintools import encode_integer, decode_integer

encoded = encode_integer(123456)
print(encoded)             # b'\x01\xe2@'

decoded = decode_integer(encoded)
print(decoded)             # 123456

๐Ÿ” Encode/Decode floats

from aplustools.data.bintools import encode_float, decode_float

f_bytes = encode_float(3.14159, precision="single")
print(decode_float(f_bytes, precision="single"))  # ~3.14159

๐Ÿ“ฆ Variable-length integer encoding

from aplustools.data.bintools import to_varint_length, read_varint_length
import io

data = to_varint_length(300)
length = read_varint_length(io.BytesIO(data))
print(length)  # 300

๐Ÿ“ Human-readable size formatting

from aplustools.data.bintools import bytes_to_human_readable_binary_iec

print(bytes_to_human_readable_binary_iec(1024))      # 1.0 KiB
print(bytes_to_human_readable_binary_iec(1048576))   # 1.0 MiB

๐Ÿ” Secure Password Generation (aplustools.security.passwords)

Create readable, secure, and crack-resistant passwords.


๐Ÿ”‘ Generate secure passwords easily

from aplustools.security.passwords import SecurePasswordGenerator

generator = SecurePasswordGenerator(security="super_strong")
pw_data = generator.passphrase()

print(pw_data["password"])     # Actual password
print(pw_data["extra_info"])   # Generation method metadata

๐Ÿ”ง Available styles

generator.sentence()         # Readable sentence
generator.pattern()          # Format like Aa99##
generator.complex_pattern()  # Pattern + random word mix
generator.complex()          # High entropy, mixed format
generator.mnemonic()         # Easy to remember

๐Ÿง  Estimate worst-case crack time

pw_data = generator.generate_secure_password(return_worst_case=True)
print(pw_data["worst_case"])  # e.g., "centuries"

โฑ Basic Timing (aplustools.package.chronokit)

Measure elapsed time with nanosecond resolution.


โฒ Use BasicTimer for simple measurements

from aplustools.package.chronokit import BasicTimer
import time

timer = BasicTimer(auto_start=True)
time.sleep(0.123)
timer.stop()

print(timer.get())          # timedelta
print(timer.get_readable()) # Human-readable

๐Ÿ“ Create precise deltas

from aplustools.package.chronokit import PreciseTimeDelta

delta = PreciseTimeDelta(seconds=1.5, microseconds=250)
print(str(delta))           # 0:00:01.500250
print(delta.to_readable())  # "1.500s"

โฑ Flexible Timing with FlexTimer

Advanced control for performance tracking, interval measurements, and benchmarking.


๐Ÿงช Measure CPU-only time (ignores sleep)

from aplustools.package.chronokit import CPUFTimer

with CPUFTimer():
    sum(i * i for i in range(100_000))

Ideal for benchmarking with minimal system interference.


๐Ÿ”„ Manual start/stop and waiting

from aplustools.package.chronokit import FlexTimer

t = FlexTimer(start_now=False)
t.start(start_at=1.2)
t.wait(0.8)
t.stop()

print(t.get().to_clock_string())  # e.g., 00:00:02.00

โฑ Record laps (interval checkpoints)

t = FlexTimer()
# ... task 1 ...
t.lap()
# ... task 2 ...
t.lap()

print(t.show_laps())  # List of lap durations

๐Ÿช„ Time entire functions with a decorator

@FlexTimer().time()
def compute():
    return [x**2 for x in range(1_000_000)]

compute()  # Prints execution time

๐Ÿ•’ Schedule callbacks after a delay

def on_done():
    print("Finished!")

FlexTimer().after(2, on_done)

๐Ÿงต Run functions at intervals

def tick():
    print("Tick!")

FlexTimer().interval(1, count=5, callback=tick)

๐Ÿ“ˆ Estimate time complexity of a function

def fn(n):
    return [i ** 2 for i in range(n)]

def gen_inputs():
    for i in range(1000, 50000, 1000):
        yield ((i,), {})

from aplustools.package.chronokit import FlexTimer
print(FlexTimer.complexity(fn, gen_inputs()))  # e.g., "O(N)"

โš™๏ธ Concurrency and Shared Memory (aplustools.io.concurrency)

Smart thread pools and safe process-shared memory.


๐Ÿงต Dynamic thread pool with auto-scaling

from aplustools.io.concurrency import LazyDynamicThreadPoolExecutor
import time

def task(i):
    time.sleep(0.5)
    return f"Task {i}"

with LazyDynamicThreadPoolExecutor(min_workers=2, max_workers=10) as pool:
    results = [f.result() for f in [pool.submit(task, i) for i in range(5)]]

print(results)

๐Ÿง  Share memory across processes with SharedStruct

from aplustools.io.concurrency import SharedStruct
from multiprocessing import Process

def increment(ref, count):
    shared = ref.dereference()
    for _ in range(count):
        with shared:
            val = shared.get_field(0)
            shared.set_field(0, val + 1)
    shared.close()

if __name__ == "__main__":
    counter = SharedStruct("i", create=True)
    counter.set_field(0, 0)

    p1 = Process(target=increment, args=(counter.reference(), 1000))
    p2 = Process(target=increment, args=(counter.reference(), 1000))
    p1.start(); p2.start(); p1.join(); p2.join()

    print("Final:", counter.get_field(0))  # 2000
    counter.close()
    counter.unlink()

๐Ÿ“Ž Struct format reference

  • "i" โ€” one 4-byte integer
  • "if" โ€” integer + float
  • "i10s" โ€” integer + 10-byte string
with SharedStruct("if", create=True) as stats:
    stats.set_data(42, 3.14)
    print(stats.get_data())  # (42, 3.14)

๐ŸŒ Web Requests (aplustools.web.request)

Make web requests in sync or async mode โ€” single or batch.


๐Ÿ”น Quick HTTPS fetch

from aplustools.web.request import fetch

data = fetch("https://httpbin.org/get")
print(data.decode())

๐Ÿ”ธ Threaded batch requests with BatchRequestHandler

from aplustools.web.request import BatchRequestHandler

handler = BatchRequestHandler(min_workers=2, max_workers=10)

# Single request
print(handler.request("https://httpbin.org/get").decode())

# Multiple (sync)
urls = ["https://httpbin.org/get"] * 5
print(len(handler.request_many(urls)))

# Multiple (async)
result = handler.request_many(urls, async_mode=True)
print(len(result.no_into().no_into_results))

handler.shutdown()

๐Ÿ’ก The thread pool can be reused via handler.pool.


โšก High-performance async requests with AioHttpRequestHandler

from aplustools.web.request import AioHttpRequestHandler

aio = AioHttpRequestHandler()

print(aio.request("https://httpbin.org/get").decode())
print(len(aio.request_many(["https://httpbin.org/get"] * 5)))

aio.shutdown()

Sync interface, but internally async. Great for sync environments that want async speed.

๐Ÿ” aplustools.security.crypto

This section demonstrates the flexible, backend-agnostic cryptography interface provided by aplustools. The section includes standard hashing, key derivation, and post-quantum encryption/signing using modern algorithms.

๐Ÿ“ฆ Setup and Imports

from aplustools.security.crypto.algos import (
    Sym,
    Asym,
    HashAlgorithm,
    KeyDerivationFunction,
)
from aplustools.security.crypto.exceptions import NotSupportedError
from aplustools.security.crypto import set_backend, Backend
import os

Set the std lib cryptography backend (you can later switch to advanced libraries like cryptography, argon2-cffi, etc.):

set_backend()  # Uses Backend.std_lib

๐Ÿ” Hashing with Standard Algorithms

Most HashAlgorithm variants support .hash(), .verify(), and .std_verify().

# MD5
h = HashAlgorithm.MD5.hash(b"hello world")
print("MD5:", h.hex())
print("Verify:", HashAlgorithm.MD5.verify(b"hello world", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))

# SHA1
h = HashAlgorithm.SHA1.hash(b"hello world")
print("SHA1:", h.hex())
print("Verify:", HashAlgorithm.SHA1.verify(b"hello world", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))

# SHA256
h = HashAlgorithm.SHA2.SHA256.hash(b"hello world")
print("SHA256:", h.hex())
print("Verify:", HashAlgorithm.SHA2.SHA256.verify(b"hello world", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))

# SHA3-256
h = HashAlgorithm.SHA3.SHA256.hash(b"hello world")
print("SHA3-256:", h.hex())
print("Verify:", HashAlgorithm.SHA3.SHA256.verify(b"hello world", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello world", h))

โš–๏ธ Hashing with Variable-Length and Specialized Algorithms

Some algorithms require an output length (e.g., SHAKE128, BLAKE2s):

# SHAKE128 (8 bytes)
h = HashAlgorithm.SHA3.SHAKE128.hash(b"hello", 8)
print("SHAKE128:", h.hex())
print("Verify:", HashAlgorithm.SHA3.SHAKE128.verify(b"hello", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))

# BLAKE2s (8 bytes)
h = HashAlgorithm.BLAKE2.BLAKE2s.hash(b"hello", 8)
print("BLAKE2s:", h.hex())
print("Verify:", HashAlgorithm.BLAKE2.BLAKE2s.verify(b"hello", h))
print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))

Some algorithms are optional in std lib:

# RIPEMD160
try:
    h = HashAlgorithm.RIPEMD160.hash(b"hello")
    print("RIPEMD160:", h.hex())
    print("Verify:", HashAlgorithm.RIPEMD160.verify(b"hello", h))
    print("Std-Verify:", HashAlgorithm.std_verify(b"hello", h))
except Exception as e:
    print("RIPEMD160 unsupported in std_lib:", e)

๐Ÿ”‘ Key Derivation Functions (KDFs)

All KDFs support .derive(password, salt, ...) and produce fixed-length binary output:

password = b"my-password"
salt = os.urandom(16)

print("PBKDF2HMAC:", KeyDerivationFunction.PBKDF2HMAC.derive(password, salt=salt).hex())
print("PBKDF1    :", KeyDerivationFunction.PBKDF1.derive(password, salt=salt, length=16).hex())
print("Scrypt    :", KeyDerivationFunction.Scrypt.derive(password, salt=salt, length=16).hex())
print("HKDF      :", KeyDerivationFunction.HKDF.derive(password, salt=salt).hex())
print("ConcatKDF :", KeyDerivationFunction.ConcatKDF.derive(password, otherinfo=b"my-info").hex())

๐Ÿ›  Switch to Advanced Backends

Enable advanced features like post-quantum crypto and better hashing support:

set_backend(
    [
        Backend.cryptography_alpha,  # Currently only supports hashes like SHA3
        Backend.quantcrypt,          # To enable post-quantum cryptography
        Backend.argon2_cffi,         # Required for Argon2
        Backend.bcrypt,              # Required for BCrypt
        Backend.std_lib,             # Fallback
    ]
)

๐Ÿง‚ Argon2 Hashing and Verification

# Hash a password/message using Argon2
hashed = HashAlgorithm.ARGON2.hash(b"Ha", os.urandom(16))
print("\nArgon2 Hash:", hashed.decode())

# Verify the hash
is_valid = HashAlgorithm.ARGON2.verify(b"Ha", hashed)
print("Argon2 Valid:", is_valid)

try:
    print(
        "Std-Verify",
        HashAlgorithm.std_verify(
            b"Ha", hashed, fallback_algorithm="argon2", text_ids=False
        ),
    )  # Std-Verify can't decode special algos like argon2 or bcrypt
except NotSupportedError:
    print("Std-Verify failed")

๐Ÿ” BCrypt Hashing and Verification

# Hash a password with BCrypt
bcrypt_hash = HashAlgorithm.BCRYPT.hash(b"my-secret-password")
print("BCrypt Hash:", bcrypt_hash.decode())

# Verify the password against the hash
is_valid = HashAlgorithm.BCRYPT.verify(b"my-secret-password", bcrypt_hash)
print("BCrypt Valid:", is_valid)

๐Ÿ”‘ Argon2 / BCrypt for Secure Key Derivation

# Derive a key using Argon2 KDF
derived_key = KeyDerivationFunction.ARGON2.derive(b"my-password", salt=os.urandom(16))
print("Argon2 Derived Key:", derived_key.hex())

# Derive a key using BCrypt KDF
bcrypt_key = KeyDerivationFunction.BCRYPT.derive(b"my-password", salt=os.urandom(16))
print("BCrypt Derived Key:", bcrypt_key.hex())

๐Ÿ” Asymmetric Encryption: Kyber (Post-Quantum KEM)

This demonstrates a Kyber key exchange using encapsulation (sender) and decapsulation (recipient):

# Recipient generates a keypair
recipient_key = Asym.Cipher.KYBER.keypair.new("kyber1024")

# Extract public key from recipient and share it with the sender
pub_key_bytes = recipient_key.encode_public_key()
# Keys can't be regenerated and try: except: takes more space; 
# This can only happen if you do not pass one of the keys when using .decode( ... )
if pub_key_bytes is None:
    raise ValueError("recipient_key has no public key")

# Sender receives the public key and creates a key object with only the public key
sender_key = Asym.Cipher.KYBER.keypair.decode("kyber1024", public_key=pub_key_bytes)
# Sender encapsulates a shared secret for the recipient
ciphertext, shared_secret_sender = sender_key.encapsulate()

# Recipient decapsulates to recover the shared secret
shared_secret_recipient = recipient_key.decapsulate(ciphertext)

print("\n=== Kyber KEM Flow ===")
print(f"Ciphertext             : {ciphertext.hex()}")
print(f"Sender Shared Secret   : {shared_secret_sender.hex()}")
print(f"Recipient Shared Secret: {shared_secret_recipient.hex()}")
assert shared_secret_sender == shared_secret_recipient, "Shared secrets do not match!"

โœ๏ธ Asymmetric Signing: Dilithium (Post-Quantum Signature)

This demonstrates secure message signing and verification using the Dilithium signature algorithm:

# Generate the signing keypair (private + public)
sign_key = Asym.Cipher.DILITHIUM.keypair.new("dilithium5")

# Sign a message using the private key
message = b"Hello World"
signature = sign_key.sign(message)

# Extract and share only the public key
pub_key_bytes = sign_key.encode_public_key()
# Keys can't be regenerated and try: except: takes more space; 
# This can only happen if you do not pass one of the keys when using .decode( ... )
if pub_key_bytes is None:
    raise ValueError("sign_key has no public key")

# Create a new key object with only the public key for verification
verify_key = Asym.Cipher.DILITHIUM.keypair.decode(
    "dilithium5", public_key=pub_key_bytes
)
# Verify the signature using the public key
is_valid = verify_key.sign_verify(message, signature)

print("\n=== Dilithium Signature Flow ===")
print(f"Signature     : {signature.hex()}")
print(f"Signature Valid? {is_valid}")
assert is_valid, "Signature verification failed!"

aps cli

Can currently run tests with aps tests run tests/ -minimal and show a basic help using aps help.

For more detailed usage and examples, check out our documentation.

Naming convention, dependencies and library information

PEP 8 -- Style Guide for Python Code

For modules I use 'lowercase', classes are 'CapitalizedWords' and functions and methods are 'lower_case_with_underscores'.

Information

  • Additional information will be added in the full release.

Contributing

We welcome contributions! Please see our contributing guidelines for more details on how you can contribute to aplustools.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a pull request

Aps Build master

You can use the aps_build_master script for your os to make your like a lot easier. It supports running tests, installing, building and much more as well as chaining together as many commands as you like.

This example runs test, build the project and then installs it

call .\aps_build_master.bat 234
sudo apt install python3-pip
sudo apt install python3-venv
chmod +x ./aps_build_master.sh
./aps_build_master.sh 234

License

aplustools is licensed under the LGPL-2.1 License - see the LICENSE file for details.

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

aplustools-2.0.0.5.tar.gz (5.4 MB view details)

Uploaded Source

Built Distribution

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

aplustools-2.0.0.5-py3-none-any.whl (5.4 MB view details)

Uploaded Python 3

File details

Details for the file aplustools-2.0.0.5.tar.gz.

File metadata

  • Download URL: aplustools-2.0.0.5.tar.gz
  • Upload date:
  • Size: 5.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for aplustools-2.0.0.5.tar.gz
Algorithm Hash digest
SHA256 97ffe79e065a90fca6b241e715d02fd1874318f2e0eab500112e12de91217e6e
MD5 b1952f13948948073f8870eddfe462d7
BLAKE2b-256 27916cfd3b3c20c74ecba91304fcac0d6ef4dff47a70b67acc66b3b3bfe4ef86

See more details on using hashes here.

File details

Details for the file aplustools-2.0.0.5-py3-none-any.whl.

File metadata

  • Download URL: aplustools-2.0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 5.4 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for aplustools-2.0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 949568c6d498298c39ba831d1ab87f09add9d49754d7bdb4e1cc0009786fc23b
MD5 b58d95e3d3affd3c2cfd731704799303
BLAKE2b-256 986587507d844151a2474797f676136a6bdebf23315ca63722114b2016a0752c

See more details on using hashes here.

Supported by

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