====== Codeschnipsel für Python ======
Eine kleine Sammlung an Codefragmenten und Routinen für Python.
==== try main Block mit Exception Handling ====
import sys
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print('\nCtrl+C detected, will abort process')
sys.exit(0)
except Exception as e:
print('\nAn error occured during execution:')
print(e)
if '-v' or '--verbose' in sys.argv:
raise e
sys.exit(1)
==== Liste zeilenweise ausgeben ====
print(*myList, sep='\n')
==== Erstes Listenelement oder None erhalten ====
next(iter(your_list or []), None)
==== Ternärer Operator ====
print('The key is set to %s' % ('true' if key else 'false'))
==== Zeitstempel ====
import datetime
ts = str(datetime.datetime.now()).split('.')[0]
print(ts)
==== for else Beispiel ====
for i in range(1, 5):
print(i)
else:
print('The for loop is over.')
==== Temporäres Verzeichnis als Context Manager verwenden ====
import tempfile
with tempfile.TemporaryDirectory() as tmp_dir:
pass # do stuff
==== Mittels Pipe übergebene Daten lesen ====
import sys
# ensure the script only reads piped data and doesn't wait for user input
if not sys.stdin.isatty():
lst = [l.strip() for l in sys.stdin.readlines() if not l.startswith('#')]
print(lst)
==== Dateien aus einem Verzeichnis erhalten oder aus Datei lesen ====
import os
from os.path import expanduser, isdir, isfile, abspath, join as pjoin
def get_files(path=/some/path):
files = []
path = expanduser(path)
if isdir(path):
files = [pjoin(abspath(path), f) for f in os.listdir(path) if
(isfile(pjoin(path, f)) and f.lower().endswith('.ext'))]
elif isfile(path):
with open(path, 'r') as lst:
files = [l.strip() for l in lst.readlines() if not l.startswith('#') and l.split()]
return files
==== Anführungszeichen um einen String entfernen ====
def unquote(string):
"""Remove matching pair of single or double quotes around string"""
if (string[0] == string[-1]) and string.startswith(("'", '"')):
return string[1:-1]
return string
Ohne Überprüfen von passenden Angührungszeichen:
return re.sub(r'^["\']|["\']$', '', string)
==== Formatierte Ausgabe mit Einheitenpräfix ====
import re
def unit_prefix(number):
"""Format big number by using unit prefixes"""
if number >= 1000000000:
if str(number).count('0') >= 9:
return re.sub(r"000000000$", "G", str(number))
else:
return str(number/1E9) + 'G'
elif number >= 1000000:
if str(number).count('0') >= 6:
return re.sub(r"000000$", "M", str(number))
else:
return str(number/1E6) + 'M'
elif number >= 1000:
if str(number).count('0') >= 3:
return re.sub(r"000$", "k", str(number))
else:
return str(number/1E3) + 'k'
else:
return str(number)
print("{0:<20s} {1:>4d} files with {2:>4s} entries"
.format(some_string, integer, unit_prefix(integer)))
==== String splitten anhang von Trennzeichen außerhalb von Anführungszeichen ====
import re
line = "'hello world' 'foo' 'bar' '\"baz zab\"'"
delimiter = ' '
pattern = re.compile(r'''((?:[^%s"']|"[^"]*"|'[^']*')+)''' % delimiter)
print(pattern.split(line)[1::2])
==== Schleife für Eingabe von Integern ====
def input_digit(input_msg, max_retries=4, fail_msg='Invalid input, this channel will be skipped'):
"""Show the user an input dialogue to enter a digit, return 0 if it failed after max_retries"""
num, count = 0, 0
while True:
count += 1
try:
num = int(input(input_msg + ' '))
break
except ValueError:
if count < max_retries:
print("Your input wasn't a number, please try again:")
else:
print(fail_msg)
break
return num
==== Terminalgröße ermitteln ====
from subprocess import check_output
def term_size():
return list(map(int, check_output(['stty', 'size']).split()))
def term_height():
return term_size()[0]
def term_width():
return term_size()[1]
# shorter possibility:
import os
os.get_terminal_size().columns
w, h = os.get_terminal_size()
==== Binary in $PATH finden ====
import sys
from os.path import abspath
from distutils.spawn import find_executable
exe = find_executable('binary_name')
if not exe:
print('[ERROR] Binary not found in your $PATH variable!')
sys.exit(1)
else:
exe = abspath(pluto)
==== Fortschrittsanzeige ====
import sys
from math import ceil
from time import sleep
def progress(total, length=20, bar='=', empty=' '):
point = total/100
increment = total/length
for i in range(total+1): # add one as counting starts at 0
sys.stdout.write('\r')
fill = int(i/increment)
# use ceil to ensure that 100% is reached, just in case of low precision
sys.stdout.write("[%s%s] %3d%%" % (bar*fill, empty*(length-fill), ceil(i/point)))
sys.stdout.flush()
sleep(0.1)
print()
def progress_simple(total, bar='='):
point = total/100
increment = total/20
for i in range(total+1): # add one as counting starts at 0
sys.stdout.write('\r')
sys.stdout.write("[%-20s] %3d%%" % (bar*int(i/increment), ceil(i/point)))
sys.stdout.flush()
sleep(0.1)
print()
try:
total = int(sys.argv[1])
except IndexError:
total = 25
except ValueError:
exit("The given argument is not a valid number!")
except:
exit("Unknown error")
progress_simple(total)
progress(total, 40, '#', '-')
==== Verzeichnis temporär wechseln (Exception-safe) ====
from contextlib import contextmanager
import os
@contextmanager
def cd(newdir):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)
# cd using context manager and decorator
# directory is reverted even after an exception is thrown
os.chdir('/home')
with cd('/tmp'):
# ...
raise Exception("There's no place like home.")
# Directory is now back to '/home'.
==== Liste mit Inhalt einer anderen Liste filtern ====
# filter a list by checking if substring of another list is contained in entries of the list to be filtered
# here flags is some list which contain entries from the list regex --> filter matching regex from list flags
flags = ['"s/regex/looking/g"', 'options', '"s/another/regex/"', '--more flags']
regex = [unquote(flag) for flag in flags if unquote(flag).startswith('s/')]
flags = [flag for flag in flags if not any(flag for reg in regex if reg in flag)]
==== Ausgiebige Tests, ob Ordner oder Dateien existieren, inklusive Rechte ====
import os
import errno
from os.path import abspath, dirname, join as pjoin
def check_path(path, create=False, write=True):
"""Check if given path exists and is readable as well as writable if specified;
if create is true and the path doesn't exist, the directories will be created if possible"""
path = os.path.expanduser(path)
exist = os.path.isdir(path)
if not exist and create:
print("Directory '%s' does not exist, it will be created now" % path)
# try to create the directory; if it should exist for whatever reason,
# ignore it, otherwise report the error
try:
os.makedirs(path)
except OSError as exception:
if exception.errno == errno.EACCES:
print_error("[ERROR] You don't have the permission to create directories in '%s'" % dirname(path))
return False
elif exception.errno != errno.EEXIST:
raise
return True
elif not exist:
print_error("[ERROR] Directory '%s' does not exist" % path)
return False
else:
if not is_readable(path):
print_error("[ERROR] Directory '%s' is not readable" % path)
return False
if write and not is_writable(path):
print_error("[ERROR] Directory '%s' is not writable" % path)
return False
return True
def check_file(path, file):
"""Check if a file in a certain path exists and is readable;
if the file argument is omitted only path is checked, it's recommended to use
check_path instead for this case"""
path = os.path.expanduser(path)
if file is None:
if not os.path.isfile(path):
print_error("[ERROR] The file '%s' does not exist!" % (path))
return False
else:
if not is_readable(path):
print_error("[ERROR] The file '%s' is not readable!" % (path))
return False
return True
path = get_path(path, file)
if not os.path.isfile(path):
print_error("[ERROR] The file '%s' does not exist!" % path)
return False
else:
if not is_readable(path):
print_error("[ERROR] The file '%s' is not readable!" % (path))
return False
return True
def check_permission(path, permission):
"""Check if the given permission is allowed for path"""
if os.path.exists(path):
return os.access(path, permission)
else:
return False
def is_readable(path):
"""Check if path is readable"""
return check_permission(path, os.R_OK)
def is_writable(path):
"""Check if path is writable"""
return check_permission(path, os.W_OK)
def is_executable(path):
"""Check if path is executable"""
return check_permission(path, os.X_OK)
def get_path(path, file=None):
"""Get the absolute path of a given path and an optional file"""
if not file:
return abspath(os.path.expanduser(path))
return abspath(os.path.expanduser(pjoin(path, file)))
==== Ausführliches Beispiel für Verwendung von Argumenten ====
import sys
import os.path
import argparse
class Settings():
pass
def get_path(path):
return
def check_path(path, force=False):
return
def is_valid_file(parser, arg):
"""Helper function for argparse to check if a file exists"""
if not os.path.isfile(arg):
parser.error('The file %s does not exist!' % arg)
else:
#return open(arg, 'r')
return arg
def is_valid_dir(parser, arg):
"""Helper function for argparse to check if a directory exists"""
if not os.path.isdir(os.path.expanduser(arg)):
parser.error('The directory %s does not exist!' % arg)
else:
return os.path.expanduser(arg)
def main():
"""Main function, argparse demonstration"""
parser = argparse.ArgumentParser(description='Example method to demonstrate some '
'some of the capabilities of argsparse')
parser.add_argument('-c', '--config', nargs=1, metavar='config_file',
dest='config', required=True,
type=lambda x: is_valid_file(parser, x),
help='Required: Specify a config file')
parser.add_argument('-o', '--output', nargs=1, metavar='output_directory',
type=lambda x: is_valid_dir(parser, x),
help='Optional: Custom output directory')
parser.add_argument('-l', '--list', nargs='?', const=True,
help='List the amount of existing entries in files'
'in the output directory and exit; if "all" is specified'
'as an optional argument, the amount of entries will be listed')
parser.add_argument('-e', '--example-config', nargs='?', const='example.config',
help='Export an example config file and exit. '
'If no file is specified, the output will be written to "example.config"')
parser.add_argument('-n', '--number', type=int, nargs=1, metavar='integer',
help='Number of entries')
parser.add_argument('-q', '--queue', type=str, nargs=1, metavar='queue',
help='The used queue system')
parser.add_argument('-f', '--force', action='store_true',
help='Force creation of directories if they do not exist'
'or overwrite existing files')
parser.add_argument('-v', '--verbose', action='store_true',
help='Print additional output')
args = parser.parse_args()
verbose = args.verbose
force = args.force
if args.example_config:
print('[INFO] Write example config to file "%s"' % args.example_config)
sys.exit(0)
config = args.config
settings = None
if verbose:
print('Use config file %s' % config)
with open(config, 'r') as conf:
settings = settings.read_config(conf)
if args.list:
if verbose and args.list == 'all':
print('Trying to determine the total amount file entries')
if args.output:
settings.set('OUTPUT_PATH', get_path(args.output[0]))
list_file_amount(settings, args.list == 'all')
sys.exit(0)
if args.queue:
if verbose:
print('Use the queue', args.queue[0])
settings.set('QUEUE', args.queue[0])
if args.number:
if verbose:
print('%d entries specified', args.number[0])
settings.set('NUMBER', args.number[0])
if verbose:
print('The following settings will be used:')
settings.print()
if args.output:
if not check_path(args.output[0], force):
sys.exit('The output directory %s cannot be used' % args.output[0])
output = get_path(args.output[0])
print('Setting custom output directory: %s' % output)
==== Farbige Ausgaben und Logging ====
#!/usr/bin/env python
# vim: set ai ts=4 sw=4 sts=4 noet fileencoding=utf-8 ft=python
'''
This module provides functions to color string in the terminal output
and provides a logging class with colored strings
'''
__version__ = '1.0'
# Colored output
#The background is set with 40 plus the number of the color, and the foreground with 30
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
#These are the sequences need to get colored ouput
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
COLORS = {
'WARNING': YELLOW,
'INFO': WHITE,
'DEBUG': BLUE,
'CRITICAL': YELLOW,
'ERROR': RED,
'RED': RED,
'GREEN': GREEN,
'YELLOW': YELLOW,
'BLUE': BLUE,
'MAGENTA': MAGENTA,
'CYAN': CYAN,
'WHITE': WHITE
}
def color_string(string, color):
fmt = ''
if color in COLORS:
fmt = COLOR_SEQ % (30 + COLORS[color]) + string + RESET_SEQ
elif color in range(8):
fmt = COLOR_SEQ % (30 + color) + string + RESET_SEQ
else:
fmt = string
return fmt
def bold_string(string):
return BOLD_SEQ + string + RESET_SEQ
def print_color(string, color):
print(color_string(string, color))
import sys
def print_error(string):
print(color_string(string, RED), file=sys.stderr)
import logging
class ColoredFormatter(logging.Formatter):
def __init__(self, *args, **kwargs):
# can't do super(...) here because Formatter is an old school class
logging.Formatter.__init__(self, *args, **kwargs)
def format(self, record):
levelname = record.levelname
color = COLOR_SEQ % (30 + COLORS[levelname])
record.levelname = levelname.center(8)
message = logging.Formatter.format(self, record)
message = message.replace("$RESET", RESET_SEQ)\
.replace("$BOLD", BOLD_SEQ)\
.replace("$COLOR", color)
for k,v in COLORS.items():
message = message.replace("$" + k, COLOR_SEQ % (v+30))\
.replace("$BG" + k, COLOR_SEQ % (v+40))\
.replace("$BG-" + k, COLOR_SEQ % (v+40))
return message + RESET_SEQ
# Custom logger class with multiple destinations
class ColoredLogger(logging.Logger):
FORMAT = "[%(asctime)s][$COLOR%(levelname)s$RESET] $BOLD%(message)s$RESET (%(filename)s:%(lineno)d)"
# format with milliseconds (only 3 digits) using dot instead of comma, DATEFORMAT below needed to remove milliseconds from asctime
#FORMAT = "[%(asctime)s.%(msecs).03d][$COLOR%(levelname)s$RESET] $BOLD%(message)s$RESET (%(filename)s:%(lineno)d)"
DATEFORMAT = '%Y-%m-%d %H:%M:%S'
def __init__(self, name):
logging.Logger.__init__(self, name, logging.DEBUG)
color_formatter = ColoredFormatter(self.FORMAT)
# milliseconds won't be shown with the below command
#color_formatter = ColoredFormatter(fmt=self.FORMAT, datefmt=self.DATEFORMAT)
console = logging.StreamHandler()
console.setFormatter(color_formatter)
self.addHandler(console)
return
logging.setLoggerClass(ColoredLogger)
logger = logging.getLogger('Simulation')
logger.setLevel(logging.DEBUG)
logger.warning("This is a warning")
logger.error("ERROR!")
logger.info("Just an info")
logger.critical("Oh oh")
logger.debug("Debug message")
print_color("just a cyan colored info", 'CYAN')
print_color("and a magenta/purple one, too", MAGENTA)
print_error('[ERROR] This will be written to stderr')
#str = "this is a test string"
#for i in range(8):
# print(COLOR_SEQ % (30 + i) + str + RESET_SEQ)
==== subprocess Beispiele ====
#!/usr/bin/env python
import subprocess
# use sequence of arguments
ret = subprocess.call(['echo', 'Hello world!'])
# shell=True allows to use simple string for the command
ret = subprocess.call('echo Hello world!', shell=True)
print()
command = 'date'
print(command)
# checks output, raises error if nonzero return code
output = subprocess.check_output(command, shell=True)
p = subprocess.Popen('date', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate()
returncode = p.returncode
#return_code = p.wait()
print(output.decode('utf-8'))
print('out:', output.decode('utf-8'))
print('err:', err.decode('utf-8'))
print('status:', returncode)
# write to stdout and logfile
logfile = open('logfile', 'w')
proc=subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
sys.stdout.write(line)
logfile.write(line)
proc.wait()
{{tag>python programming}}