CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-clint

Python Command Line Interface Tools for colored output, progress bars, text formatting, and argument handling

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utilities.mddocs/

Unix Pipes and Utilities

Unix pipe detection, path expansion utilities, collection testing, and directory creation helpers. This module provides essential utility functions for file system operations, data type checking, and string manipulation commonly needed in CLI applications.

Capabilities

Unix Pipe Detection

Detect and read data piped to the application via stdin, enabling CLI tools to work in Unix pipe chains.

def piped_in():
    """
    Detect and return data piped to the application via stdin.
    
    Returns:
        str or None: Content from stdin if data is piped, None otherwise
    
    Usage:
        Enables CLI applications to work in Unix pipe chains like:
        cat file.txt | python app.py
        echo "data" | python app.py
    """

Usage Examples:

from clint.pipes import piped_in
from clint.textui import puts

# Check for piped input
input_data = piped_in()
if input_data:
    puts(f"Received piped data: {len(input_data)} characters")
    # Process the piped data
    for line in input_data.splitlines():
        puts(f"Processing: {line}")
else:
    puts("No piped input detected")

# CLI tool that works with or without pipes
def main():
    piped_data = piped_in()
    if piped_data:
        # Process piped data
        process_input(piped_data)
    else:
        # Interactive mode or file processing
        filename = input("Enter filename: ")
        with open(filename) as f:
            process_input(f.read())

Path Expansion

Expand user paths, environment variables, directories, and glob patterns into complete file lists.

def expand_path(path):
    """
    Expand directories and globs in given path to list of files.
    
    Args:
        path (str): Path with potential user shortcuts, env vars, directories, or globs
    
    Returns:
        list: List of expanded file paths matching the input pattern
    
    Expansion includes:
        - User home directory (~)
        - Environment variables ($HOME, etc.)
        - Directory traversal (returns all files in directory)
        - Glob patterns (*.txt, **/*.py, etc.)
    """

Usage Examples:

from clint.utils import expand_path

# Expand user home directory
files = expand_path('~/Documents/*.txt')
# Returns: ['/home/user/Documents/file1.txt', '/home/user/Documents/file2.txt']

# Expand environment variables
files = expand_path('$HOME/projects/**/*.py')
# Returns all Python files in projects directory and subdirectories

# Expand directory to all contained files
files = expand_path('/etc/nginx/')
# Returns: ['/etc/nginx/nginx.conf', '/etc/nginx/sites-available/default', ...]

# Glob patterns
files = expand_path('/var/log/*.log')
# Returns: ['/var/log/system.log', '/var/log/app.log', ...]

# Use in CLI applications
import sys
from clint.arguments import Args

args = Args()
for pattern in args.all:
    for filepath in expand_path(pattern):
        print(f"Processing: {filepath}")
        # Process each file

Collection Testing

Test whether an object is a collection type, excluding strings which are treated as atomic values.

def is_collection(obj):
    """
    Test if an object is a collection. Strings don't count as collections.
    
    Args:
        obj: Any Python object to test
    
    Returns:
        bool: True if object is a collection (list, tuple, set, etc.) but not a string
    
    Note:
        Strings are explicitly excluded because they are iterable but typically
        treated as atomic values in CLI contexts rather than collections.
    """

Usage Examples:

from clint.utils import is_collection

# Test various types
print(is_collection([1, 2, 3]))          # True - list
print(is_collection((1, 2, 3)))          # True - tuple
print(is_collection({1, 2, 3}))          # True - set
print(is_collection({'a': 1, 'b': 2}))   # True - dict
print(is_collection("hello"))            # False - string
print(is_collection(42))                 # False - int
print(is_collection(range(5)))           # True - range object

# Use in argument processing
def process_args(*args):
    for arg in args:
        if is_collection(arg):
            # Handle collections (lists, tuples, etc.)
            for item in arg:
                process_item(item)
        else:
            # Handle atomic values (strings, numbers, etc.)
            process_item(arg)

# CLI application usage
from clint.arguments import Args
args = Args()

for arg_value in args.all:
    if is_collection(arg_value):
        print(f"Collection with {len(arg_value)} items")
    else:
        print(f"Single value: {arg_value}")

Directory Creation

Create directories recursively, similar to the Unix mkdir -p command.

def mkdir_p(path):
    """
    Create directory and any necessary parent directories (like 'mkdir -p').
    
    Args:
        path (str): Directory path to create
    
    Side Effects:
        Creates the directory and all parent directories as needed
        Does nothing if directory already exists (no error)
    
    Raises:
        OSError: If directory creation fails for reasons other than already existing
    """

Usage Examples:

from clint.utils import mkdir_p

# Create nested directories
mkdir_p('/tmp/my-app/data/logs')  # Creates all intermediate directories

# Safe to call on existing directories
mkdir_p('/tmp/my-app/data/logs')  # No error, does nothing

# Use in application setup
import os
from clint import resources

def setup_app_directories():
    app_base = os.path.expanduser('~/.myapp')
    mkdir_p(os.path.join(app_base, 'config'))
    mkdir_p(os.path.join(app_base, 'cache'))
    mkdir_p(os.path.join(app_base, 'logs'))
    mkdir_p(os.path.join(app_base, 'plugins'))

# Error handling
try:
    mkdir_p('/root/protected/directory')
except OSError as e:
    print(f"Failed to create directory: {e}")

String Manipulation

Advanced string splitting and chunking utilities for text processing.

def tsplit(string, delimiters):
    """
    Split string using multiple delimiters (like str.split but with multiple delimiters).
    
    Args:
        string (str): String to split
        delimiters (tuple or list): Multiple delimiter characters/strings
    
    Returns:
        list: List of string parts split by any of the delimiters
    """

def schunk(string, size):
    """
    Split string into fixed-size chunks.
    
    Args:
        string (str): String to split into chunks
        size (int): Size of each chunk
    
    Returns:
        list: List of string chunks, each of specified size (last may be shorter)
    """

Usage Examples:

from clint.utils import tsplit, schunk

# Split by multiple delimiters
text = "apple,banana;orange:grape"
parts = tsplit(text, (',', ';', ':'))
# Returns: ['apple', 'banana', 'orange', 'grape']

# Parse CSV-like data with multiple separators
data = "name=John|age=25;city=NYC,country=USA"
fields = tsplit(data, ('|', ';', ','))
# Returns: ['name=John', 'age=25', 'city=NYC', 'country=USA']

# Process log entries with various separators
log_line = "2023-01-01 12:00:00 ERROR: Database connection failed"
parts = tsplit(log_line, (' ', ':', '-'))
# Returns: ['2023', '01', '01', '12', '00', '00', 'ERROR', '', 'Database', 'connection', 'failed']

# Chunk large strings for processing
large_text = "A" * 1000
chunks = schunk(large_text, 100)
# Returns: ['A' * 100, 'A' * 100, ..., remaining A's]

# Process data in fixed-size blocks
def process_in_chunks(data, chunk_size=1024):
    chunks = schunk(data, chunk_size)
    for i, chunk in enumerate(chunks):
        print(f"Processing chunk {i+1}/{len(chunks)}: {len(chunk)} characters")
        # Process each chunk

# Format data for display
def format_hex_dump(data, width=16):
    hex_chars = data.encode('hex') if hasattr(data, 'encode') else data.hex()
    chunks = schunk(hex_chars, width * 2)  # 2 hex chars per byte
    for i, chunk in enumerate(chunks):
        offset = i * width
        formatted_hex = ' '.join(schunk(chunk, 2))
        print(f"{offset:08x}: {formatted_hex}")

Complete Usage Examples

CLI Tool with Pipe Support

#!/usr/bin/env python
from clint.pipes import piped_in
from clint.utils import expand_path, is_collection
from clint.arguments import Args
from clint.textui import puts, colored

def main():
    args = Args()
    
    # Check for piped input first
    piped_data = piped_in()
    if piped_data:
        puts(colored.green("Processing piped data..."))
        process_text(piped_data)
        return
    
    # Process file arguments
    if args.files:
        for file_pattern in args.files:
            file_paths = expand_path(file_pattern)
            for file_path in file_paths:
                puts(f"Processing: {file_path}")
                with open(file_path) as f:
                    process_text(f.read())
    else:
        puts(colored.red("No input provided. Use: program < file.txt or program *.txt"))

def process_text(text):
    # Process the text data
    lines = text.splitlines()
    puts(f"Processing {len(lines)} lines of text")

if __name__ == '__main__':
    main()

Application Setup Utility

from clint.utils import mkdir_p, expand_path, is_collection
from clint import resources
import os

def setup_application(app_name, config_files=None):
    """Set up application directories and copy configuration files."""
    
    # Initialize application directories
    resources.init("MyCompany", app_name)
    
    # Create additional subdirectories
    mkdir_p(resources.user.path + "/plugins")
    mkdir_p(resources.user.path + "/themes")
    mkdir_p(resources.cache.path + "/downloads")
    
    # Copy configuration files if provided
    if config_files:
        if not is_collection(config_files):
            config_files = [config_files]
        
        for config_pattern in config_files:
            config_paths = expand_path(config_pattern)
            for config_path in config_paths:
                filename = os.path.basename(config_path)
                with open(config_path) as f:
                    resources.user.write(f"config/{filename}", f.read())
                print(f"Copied config: {filename}")

# Usage
setup_application("MyApp", ["~/.myapp-configs/*.ini", "/etc/myapp/defaults/*"])

Install with Tessl CLI

npx tessl i tessl/pypi-clint

docs

arguments.md

colored-text.md

english.md

index.md

progress.md

prompts.md

resources.md

text-output.md

utilities.md

validation.md

tile.json