def get_record_extremes(type_): ''' Get global date/data min/max. type_ can be "time" or "data" status: finished return: tuple raise: IndexError, ValueError ''' try: minimum = skj_std.arguments_values['source'][0][type_ + '_min'] maximum = minimum except (IndexError, KeyError) as exception_msg: raise IndexError(skj_std.create_error_msg("INTERNAL", exception_msg)) for f in skj_std.arguments_values['source']: maximum = max(maximum, f[type_ + '_max']) minimum = min(minimum, f[type_ + '_min']) if type_ == "time": from time import strftime try: maximum = strftime(skj_std.arguments_values['timeformat'], maximum) minimum = strftime(skj_std.arguments_values['timeformat'], minimum) except (ValueError, TypeError) as exception_msg: raise ValueError(skj_std.create_error_msg("INTERNAL", exception_msg)) return maximum, minimum
def check_effects_syntax(): ''' Check for allowed syntax status: finished return: dict raise: ValueError ''' valid_effects = dict() f = skj_std.arguments_values['effectparams'] # wtf is this mess, right? u = [l.split(":") for l in f] # well, if I'll ever want to piss someone in team... c = [f for l in u for f in l] # ... i'll play on stubborn, selfish asshole ... k = [f.split("=") for f in c] # ... and write my code just like folks at MFF ... _ = {e[0]:e[1] for e in k if len(e) > 1} # ... write math! parsed_effects = _ # ouky douky, lets get back to work for effect in parsed_effects: if effect in skj_std.allowed_effects: if parsed_effects[effect] in skj_std.allowed_effects[effect]: valid_effects[effect] = parsed_effects[effect] continue if skj_std.arguments_values['ignoreerrors']: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("INVALID_VALUE", effect)) else: raise ValueError(skj_std.create_error_msg("INVALID_VALUE", effect)) return valid_effects
def check_file(file_, ignorable_=True, verbose_=True): ''' Check if file exists && is readable && not empty status: finished return: file_ / None raise: IOError ''' try: with open(file_, mode="r", encoding="utf-8") as f: # If file exists && is readable... from os.path import isfile if not isfile(file_): # ... && is a normal file (no block device, etc) ... raise OSError("File " + file_ + " is not a regular file") from os import stat if stat(f.fileno()).st_size <= 0: # ... && is not empty ... raise OSError("File " + file_ + " is empty") f.readline() # ... && is really an unicode file ... except (IOError, TypeError, OSError, UnicodeDecodeError) as exception_msg: if skj_std.arguments_values['ignoreerrors'] and ignorable_ == True: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("PYTHON", exception_msg)) return None else: raise IOError(skj_std.create_error_msg("PYTHON", exception_msg, False)) else: return file_ # ... then it has passed all basic tests
def determine_anim_type(): ''' Decide whether animation is multiplot type or oneline status: finished return: str raise: IndexError ''' try: time_max = skj_std.arguments_values['source'][0] time_min = skj_std.arguments_values['source'][0] except IndexError as exception_msg: raise IndexError(skj_std.create_error_msg("INTERNAL", exception_msg)) for source_file in skj_std.arguments_values['source']: if source_file['time_min'] < time_min['time_min']: time_min = source_file if source_file['time_max'] >= time_max['time_max']: time_max = source_file # If the file with new min can also have new max, use it ... elif source_file['time_max'] > time_max['time_max']: time_max = source_file if source_file['time_min'] <= time_min['time_min']: time_min = source_file # ... because of correct anim type detection if time_max["path"] == time_min["path"] and len(skj_std.arguments_values['source']) != 1: # Hope this works return "multiplot" return "oneline"
def set_animation_properties(): ''' Set properties of animation like speed, time, num of frames, num of records, type, etc status: finished return: None raise: TypeError, IndexError, ValueError ''' # Get animation type skj_std.arguments_values['animation_type'] = determine_anim_type() # raise IndexError # Then calculate the number of valid lines (valid line is also called 'record') skj_std.arguments_values['records'] = 0 # File with zero records should never exist for lines_file in get_anim_records(): if skj_std.arguments_values['animation_type'] == "multiplot": # Multiplot animation has as many records as the longest file has lines if lines_file > skj_std.arguments_values['records']: skj_std.arguments_values['records'] = lines_file else: # Oneline animation has sum(all_lines) records skj_std.arguments_values['records'] += lines_file # Calculate correct speed && fps && frames && time calculate_sfft() # raise VauleError, ArithmeticError (catch AE? => if ignoreerrors: speed = 0 (see code below)) # Correct speed/fps if it is too low (< 1), cause that leads to crazy long create_speed_seq() && generate_anim() if skj_std.arguments_values['speed'] < 1 or skj_std.arguments_values['fps'] < 1: if skj_std.arguments_values['ignoreerrors']: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("TOO_SMALL_ANIM", \ str(skj_std.arguments_values['speed']) + \ "/" + str(skj_std.arguments_values['fps']))) skj_std.arguments_values['speed'] = skj_std.arguments_defaults['speed'] skj_std.arguments_values['fps'] = skj_std.arguments_defaults['fps'] skj_std.arguments_values['time'] = skj_std.arguments_defaults['time'] calculate_sfft() else: raise ValueError(skj_std.create_error_msg("TOO_SMALL_ANIM", \ str(skj_std.arguments_values['speed']) + "/" + str(skj_std.arguments_values['fps']))) # Create sequence of records added to every created frame from math import modf try: # Divide the speed on it's integer and fractional parts speed_fraction = modf(skj_std.arguments_values['speed'])[0] speed_integer = int(modf(skj_std.arguments_values['speed'])[1]) except TypeError as exception_msg: raise TypeError(skj_std.create_error_msg("INTERNAL", exception_msg)) for source_file in skj_std.arguments_values['source']: # Add the sequence to each file's properties source_file['adding_seq'] = create_speed_seq(file_=source_file, int_=speed_integer, frac_=speed_fraction)
def check_time_format(datetime_, ignorable_=True, verbose_=True): ''' Check if string containing date and time is in the specified format. status: finished return: time_struct / None raise: ValueError ''' from time import strptime try: ret = strptime(datetime_[0], datetime_[1]) except (ValueError, TypeError, IndexError) as exception_msg: if skj_std.arguments_values['ignoreerrors'] and ignorable_ == True: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("PYTHON", exception_msg)) return None else: raise ValueError(skj_std.create_error_msg("PYTHON", exception_msg, False)) else: return ret
def check_command_exists(command_, ignorable_=True): ''' Check for command_ existence && executability status: finished return: command_ / None raise: OSError ''' import subprocess try: subprocess.call(command_, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT, timeout=5) except (subprocess.TimeoutExpired, subprocess.SubprocessError, OSError, ValueError, TypeError) as exception_msg: if skj_std.arguments_values['ignoreerrors'] and ignorable_ == True: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("PYTHON", exception_msg)) return None else: raise OSError(skj_std.create_error_msg("PYTHON", exception_msg, False)) else: return command_
def check_float_ok(float_, ignorable_=True, verbose_=True): ''' Check if string is float and not inf/nan status: finished return: float / None raise: ValueError ''' from math import isinf, isnan try: if isnan(float(float_)) or isinf(float(float_)): raise ValueError("value is inf/nan in a place where actual number should be") except (ValueError, TypeError) as exception_msg: if skj_std.arguments_values['ignoreerrors'] and ignorable_ == True: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("PYTHON", exception_msg)) return None else: raise ValueError(skj_std.create_error_msg("PYTHON", exception_msg, False)) else: return float(float_)
def create_animation(): ''' Finally, call ffmpeg and let it do it's magic status: finished return: None raise: OSError ''' import os import subprocess from sys import argv if skj_std.arguments_values['name'] == skj_std.arguments_defaults['name']: skj_std.arguments_values['name'] = os.path.split(argv[0])[1] output = os.path.join(os.getcwd(), skj_std.arguments_values['name']) # Output directory if os.path.isdir(output): i = 0 # If the dir already exists ... output = output + '_' + str(i) while os.path.isdir(output): i += 1 # ... try output_i where i = max(i,0) + 1 output = output[:output.rfind('_')] + '_' + str(i) try: os.makedirs(output) # If we do not have write/execute in os.getcwd()... except OSError as exception_msg: if skj_std.arguments_values['ignoreerrors']: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("OUTPUT_DIR_CREATE", output)) output = skj_std.temp_directories['root'] # ... move output to temp dir we already have ... else: # ... or die! raise OSError(skj_std.create_error_msg("OUTPUT_DIR_CREATE", output)) filetype = ".mp4" codec = "libx264" ffmpeg = ["ffmpeg", "-f", "image2", "-r", str(skj_std.arguments_values['fps']), "-i", \ os.path.join(skj_std.temp_directories['gnuplot'], "g_%0" + \ str(len(str(skj_std.arguments_values['frames']))) + "d.png"), "-c:v", codec, "-r", str(skj_std.arguments_values['fps']), \ os.path.join(output, skj_std.arguments_values['name'].split('/')[-1]) + filetype] try: subprocess.check_call(ffmpeg, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except subprocess.CalledProcessError as exception_msg: raise OSError(skj_std.create_error_msg("PYTHON", exception_msg))
def parse_directives(): ''' Parse configuration file directives status: finished return: None raise: IOError ''' config_file = dict() for argument in skj_std.arguments_repeatable: config_file[argument] = list() try: with open(skj_std.arguments_values['config'], mode="r", encoding="utf-8") as cnf_file: for line in cnf_file: option = line.partition('#')[0].strip().split(None, 1) if len(option) > 0: # Check if it is a valid directive if option[0].lower() not in skj_std.arguments_defaults: raise ValueError(option[0] + " is not a configuration directive") if len(option) == 1: raise ValueError(option[0] + " does not have configuration value") if option[0].lower() in ["speed", "fps", "time"]: # should be created as list of floats from argparse from skj_checker_common import check_float_ok option[1] = check_float_ok(option[1]) # Check && convert string to float if possible # Store valid directives if option[0].lower() in skj_std.arguments_repeatable: config_file[option[0].lower()].append(option[1]) else: config_file[option[0].lower()] = option[1] except (IOError, IndexError, TypeError, ValueError) as exception_msg: if skj_std.arguments_values['ignoreerrors']: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("PYTHON", exception_msg)) return else: raise IOError(skj_std.create_error_msg("PYTHON", exception_msg, False)) else: add_directives_to_args(config_file, skj_std.arguments_repeatable)
def check_y(type_, default_): ''' Check if string is "auto"/"max/min"/float. status: finished return: None raise: ValueError ''' if type_ == "max": # As we are checking for two values, we have to decide which one is it now first to_check = skj_std.arguments_values['ymax'] elif type_ == "min": to_check = skj_std.arguments_values['ymin'] else: # This should really never happen, but just to be sure raise ValueError(skj_std.create_error_msg("INTERNAL", to_check, False)) if type_ == to_check or to_check == default_: return # Problem solved, value is max/min/default if check_float_ok(to_check) == None: if type_ == "max": skj_std.arguments_values['ymax'] = default_ else: skj_std.arguments_values['ymin'] = default_
def check_x(type_, default_): ''' Check if string is "auto"/"max/min"/time_string. status: finished return: None raise: ValueError ''' if type_ == "max": # As we are checking for two values, we have to decide which one is it now first to_check = skj_std.arguments_values['xmax'] elif type_ == "min": to_check = skj_std.arguments_values['xmin'] else: # This should really never happen, but just to be sure raise ValueError(skj_std.create_error_msg("INTERNAL", to_check, False)) if to_check == "auto" or to_check == default_: return # Problem solved, value is not in date-time format if not check_time_format((to_check, skj_std.arguments_values['timeformat'])): if type_ == "max": skj_std.arguments_values['xmax'] = default_ else: skj_std.arguments_values['xmin'] = default_
def calculate_sfft(): ''' Calculate speed (num of records read each gnuplot iteration), fps, animation duration and num of frames status: devel - those if-chanins should be gone return: None raise: ValueError, ArithmeticError ''' # 0. No user input # 1. User speed && fps # 2. User speed # 3. User fps if (skj_std.arguments_values['time'] == skj_std.arguments_defaults['time'] and\ skj_std.arguments_values['speed'] == skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] == skj_std.arguments_defaults['fps']) or\ (skj_std.arguments_values['speed'] != skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] != skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] == skj_std.arguments_defaults['time']) or\ (skj_std.arguments_values['speed'] != skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] == skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] == skj_std.arguments_defaults['time']) or\ (skj_std.arguments_values['speed'] == skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] != skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] == skj_std.arguments_defaults['time']): # Calculate animation time try: skj_std.arguments_values['time'] = skj_std.arguments_values['records'] / \ (skj_std.arguments_values['speed'] * skj_std.arguments_values['fps']) except (ArithmeticError, ZeroDivisionError) as exception_msg: raise ArithmeticError(skj_std.create_error_msg("PYTHON", exception_msg)) # 0. User speed && time # 1. User time elif (skj_std.arguments_values['speed'] != skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] == skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] != skj_std.arguments_defaults['time']) or\ (skj_std.arguments_values['speed'] == skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] == skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] != skj_std.arguments_defaults['time']): # Calculate animation fps try: skj_std.arguments_values['fps'] = skj_std.arguments_values['records'] / \ (skj_std.arguments_values['speed'] * skj_std.arguments_values['time']) except (ArithmeticError, ZeroDivisionError) as exception_msg: raise ArithmeticError(skj_std.create_error_msg("PYTHON", exception_msg)) # User time && fps elif skj_std.arguments_values['speed'] == skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] != skj_std.arguments_defaults['fps'] and\ skj_std.arguments_values['time'] != skj_std.arguments_defaults['time']: # Calculate animation speed try: skj_std.arguments_values['speed'] = skj_std.arguments_values['records'] / \ (skj_std.arguments_values['fps'] * skj_std.arguments_values['time']) except (ArithmeticError, ZeroDivisionError) as exception_msg: raise ArithmeticError(skj_std.create_error_msg("PYTHON", exception_msg)) # User time && speed && fps elif skj_std.arguments_values['time'] != skj_std.arguments_defaults['time'] and\ skj_std.arguments_values['speed'] != skj_std.arguments_defaults['speed'] and\ skj_std.arguments_values['fps'] != skj_std.arguments_defaults['fps']: # Calculate correct time try: time_check = skj_std.arguments_values['records'] / \ (skj_std.arguments_values['speed'] * skj_std.arguments_values['fps']) except (ArithmeticError, ZeroDivisionError) as exception_msg: raise ArithmeticError(skj_std.create_error_msg("PYTHON", exception_msg)) # Check if correct time matches user time if time_check != skj_std.arguments_values['time']: if skj_std.arguments_values['ignoreerrors']: skj_std.print_msg_verbose(err_=skj_std.create_error_msg("INVALID_VALUE", \ skj_std.arguments_values['time'])) skj_std.arguments_values['time'] = time_check else: raise ValueError(skj_std.create_error_msg("INVALID_VALUE", skj_std.arguments_values['time'])) from math import ceil skj_std.arguments_values['frames'] = ceil(skj_std.arguments_values['records'] / skj_std.arguments_values['speed'])
from skj_checker_common import check_parsed_args try: # If we have alived the user input so far, now do some REAL user input checks check_parsed_args() except (OSError, IOError, ValueError) as exception_msg: skj_std.exit_with_failure(exception_msg, "ARGS_ERR_CHECK") from skj_subprocess_gnuplot import set_file_properties try: # Convert simple list of file names to more complex structures containing file properties for source_file in list(skj_std.arguments_values['source']): file_properties = set_file_properties(source_file) skj_std.arguments_values['source'].pop(0) if file_properties != None: # This filters files with only whitespaces skj_std.arguments_values['source'].append(file_properties) if not skj_std.arguments_values['source']: raise ValueError(skj_std.create_error_msg("NO_SOURCE", skj_std.arguments_values['source'], False)) except ValueError as exception_msg: skj_std.exit_with_failure(exception_msg, "SET_FILE_PROPERTIES") from skj_animation import set_animation_properties try: # set animation properties (S/F/T, adding seq for each file, num of frames for each file, etc) set_animation_properties() except (ValueError, IndexError, TypeError, ArithmeticError) as exception_msg: skj_std.exit_with_failure(exception_msg, "SET_ANIM_PROPERTIES") from skj_subprocess_gnuplot import draw_animation_frames try: # Do not forget that this deletes the whole adding_seq for each file if type multiplot ... draw_animation_frames() # ... but that is okay, it will no longer be needed except (IndexError, ValueError) as exception_msg: