Seriously the cats ass. Seriously.
CatsAss is the cats ass for replacing multiple prints in simple debugging situations.
Requires Python 3.6
import os.path
from pprint import pformat
__author__ = "Duroktar"
__license__ = "MIT"
This function is the_cats_ass. That's an over-statement.
def the_cats_ass():
This is an under-statement. See what I did there? What you can do here is save the sys.ENVIRONMENT by reducing print-ed waste. Mew.
returns: probably what you want
return __cat_whisperer()[Cat.ASS]
Filter the results of poking the cat. Takes variable names as strings for the args.
cat: the_cats_ass() or similar
brush: the variables you wish to see (as strings)
returns: hairballs
def comb(cat, *brush):
return PrettyKitty(cat.ctx, {k: v for k, v in cat.values.items()
if k in brush})
Omit any undesirable variables from the result.
cat: the_cats_ass() or similar
undesirables: variables you wish to have omitted (as strings)
returns: from whence it came
def avoid(cat, *undesirables):
return PrettyKitty(cat.ctx, {k: v for k, v in cat.values.items()
if k not in undesirables})
You really shouldn't be poking cats. But if you insist, it is recommended to bring catnip as it's not unusual for cats to attack dicks who poke them.
where: I leave this as an exercise for the reader. But a word of wisdom from my 1st grade teacher: never do anything that you wouldn't want to be caught dead doing. Sadly he went to jail not long after whispering those words in my ear.
catnip: catnip can grow in the wild in many places around the world. If no catnip can readily be found in yours or any of your neighbors yards then just pass True as the argument.
returns: possibly what you want.
def poke_the_cat(where, catnip=False):
if not catnip:
from random import randint
class BadCat(InterruptedError):
pass
if randint(1, 10) == 7:
mew = "You attempt to poke the cat but it attacks. " \
"Maybe if you gave it some catnip?"
raise BadCat(mew)
return __cat_whisperer()[where]
Peek in the box for a 50/50 shot of retrieving your desired output, while the other half of the time the cat is dead and the function returns nothing at all. If you decide not to peek, the cat -being neither dead nor alive- responds with random nonsense.
peek: whether to peek in the box
returns: depends
def schrodingers_cat(peek=False):
from random import choice, randint
if peek:
if randint(1, 10) % 2 == 0:
RIP
return "Nothing at all"
else:
return poke_the_cat(Cat.LEGS, catnip=True)
else:
garbled_cries = "mew meow wokka beocat ekkie".split()
return choice(garbled_cries)
__LIBDIR__ = os.path.abspath(os.path.dirname(__file__))
I can has repr?
class PrettyKitty:
def __init__(self, ctx, values, cat=None, logo=None,
marker='|/', logo_offset=-6,
formatter=pformat):
The callers name usually.
self.ctx = ctx
The local variables data.
self.values = values
The line where the talk bubble should start must end with the marker, or the data will be printed just below the logo, which may not be what you want.
self.marker = marker
Other formatters can be swapped in, JSON -for example- should work, or yaml.
self.formatter = formatter
Allows the logo to be offset to either side; negative numbers move it left and positive numbers move it right.
self.logo_offset = logo_offset
if cat is None:
cat = open(os.path.join(__LIBDIR__, 'octocat'), 'r').readlines()
self.cat = cat
if logo is None:
logo = open(os.path.join(__LIBDIR__, 'logo'), 'r').readlines()
self.logo = logo
def haz_format(self):
from shutil import get_terminal_size
cat = self.cat
logo = self.logo
marker = self.marker
logo_offset = self.logo_offset
pivot = max(len(i) for i in cat)
term_width, term_height = get_terminal_size((80, 30))
data = self.formatter({self.ctx: self.values}, width=(80-pivot)).splitlines()
logo_height = len(logo)
speak_line = [i - 1 for i, v in enumerate(cat) if v.strip().endswith(marker)]
if not speak_line:
speak_line = [logo_height + 1]
speak_line = speak_line[0]
if logo_height > speak_line:
logo = ["CatsAss".center(20)]
def rfill_lines(filler, start=0, offset=0):
height = len(filler)
for i in range(height):
index = start + i
try:
line = cat[index]
except IndexError:
cat.append(f"{' ' * pivot}"
f"{filler[i]}")
else:
l_break = '\n'
new_l = (f"{line.rstrip(l_break)}"
f"{' ' * ((pivot - len(line)) + offset)}"
f"{filler[i]}")
cat[index] = new_l
def trim(l):
if len(l) > term_width - pivot:
return l[:term_width - pivot - 5] + "[...]"
return l
trimmed_data = [trim(line) for line in data]
rfill_lines(logo, offset=logo_offset)
rfill_lines(trimmed_data, start=speak_line)
return "\n".join([l.rstrip('\n')
for l in [line[:term_width]
for line in cat]])
def __repr__(self):
return self.haz_format()
Different places to poke the cat. If the wrong scope is being printed then you probably just need to poke the cat somewhere else.
class Cat:
TAIL = 0
ASS = 1
LEGS = 2
The cat whisperer is usually very solitary and private. Thus any attempts at invoking the cat whisperer directly will be met with no resistance, because this is Python, and honestly he could use the friends.
returns: whisperings of cats
def __cat_whisperer():
from inspect import currentframe
frames = []
frame = currentframe()
while frame is not None:
frame = frame.f_back
try:
c_frame = frame.f_locals.copy()
co_name = frame.f_code.co_name
except AttributeError:
break
else:
frames.append(
PrettyKitty(co_name, {k: v for k, v in c_frame.items()
if not any([k.startswith('_'), callable(v)])}))
return frames