#! /usr/bin/env python3 # encoding: utf-8 import sys # -------------------------------------------------- def import_module(path): """ Imports a python file as a module. The `path` can be relative or absolute. Based on the work of Yuval Greenfield released into the public domain. @while importing a module """ import imp import os path = os.path.expanduser(path) # remove the .py suffix mod_dirname = os.path.dirname(path) mod_filename = os.path.basename(path) if mod_filename.endswith(".py"): mod_name = mod_filename[:-3] else: # packages for example mod_name = mod_filename fd = None try: data = imp.find_module(mod_name, [mod_dirname]) module = imp.load_module(mod_name, *data) fd = data[0] finally: if fd is not None: fd.close() return module # -------------------------------------------------- def batch_gen(data, batch_size): """ Split `data` (a sequence) into sequences `batch_size` elements long. """ for i in range(0, len(data), batch_size): yield data[i:i+batch_size] # -------------------------------------------------- def console(locals, globals=None, tab_completion=True): """ Opens up a Python console. """ import code import copy import readline import rlcompleter environment = copy.copy(locals) if globals: for key, value in globals.items(): if key not in environment: environment[key] = value if tab_completion: readline.parse_and_bind("tab: complete") c = code.InteractiveConsole(environment) c.interact(banner="") # -------------------------------------------------- def debugger(): """ Drops into the Python Debugger where called. """ import pdb pdb.set_trace() # -------------------------------------------------- def hexdump(data, indent=0, offset=16, show_header=True, show_offsets=True, show_ascii=True, use_colors=True, output=sys.stdout): """ Writes a hex dump of `data` to `output`. The output text is indented with spaces and contains `offset` bytes per line. If `show_header` is True, a single line with byte numbers preceeds all output. If `show_offsets` is True, each line is prefixed with the address of the first byte of that line. If `show_ascii` is True, each line is suffixed with its ASCII representation. Unprintable characters are replaced with a dot. The `output` must implement a .write(str x) method. If `output` is None, the string is returned instead. @while creating a hex dump """ import io import math from . import text output_io = io.StringIO() if not output else output if type(data) is not bytes: raise ValueError("data must be bytes") offset_figures = math.ceil(math.log2(len(data)) / 8) * 2 if data else 2 format_str = "%%0%dx " %(offset_figures) ptr = 0 if show_header: line = [] if show_offsets: line.append("offset"[:offset_figures].ljust(offset_figures + 2)) for i in range(offset): line.append("%2x" %(i)) if show_ascii: line.append(" *{0}*".format("ASCII".center(offset, "-"))) output_io.write(" ".join(line) + "\n") while data[ptr:]: if indent: output_io.write(" " * indent) if show_offsets: output_io.write(format_str %(ptr)) hex_bytes = [] ascii_bytes = [] for local_i, i in enumerate(range(ptr, ptr+offset)): if i < len(data): c = data[i] hex_bytes.append("%02x" %(c)) if 0x20 <= c <= 0x7e: ascii_bytes.append(chr(c)) else: ascii_bytes.append(".") elif i == len(data): hex_bytes.extend([" "] * (offset - local_i)) if use_colors: output_io.write(text.render("")) output_io.write(" ".join(hex_bytes)) if use_colors: output_io.write(text.render("<.>")) if show_ascii: output_io.write(text.render(" | ") if use_colors else " |") output_io.write("".join(ascii_bytes)) output_io.write(text.render("<.>|") if use_colors else "|") output_io.write("\n") ptr += offset if not output: output_io.seek(0) return output_io.read()