def parse_target(self, section, options): """ Tries to transform a "target" into a ParseResults. Raises if not possible. """ target_str = section if 'target' in options: target_str = options['target'] print( "WARNING: Section '%s' has option 'target'. " % section + "This option will go away in the future. " + "Please use the section name as target.", ) debug("parsing target '%s'" % target_str) if "//" not in target_str: target_str = "//" + target_str parsed_target = urlparse(target_str) options['parsed_target'] = parsed_target debug(str(parsed_target)) return options
def is_correct(self, user): debug("checking directory permissions for %s" % user.pw_name) home_path = self.get_home_for_user(user) if not isdir(home_path): debug("...directory does not exist. Ignoring.") return True return S_IMODE(stat(home_path).st_mode) == self.permissions
def test_targets(self): """ Method simply runs tests for every section. """ for section, options in self.configs.items(): debug("do check for %s" % section) options['strategy'].do_check()
def allocate_camera(self, url): debug(f"=== init_camera ===") r = self.ping(url) if r == 200: self.init = True self.url = url return r
def check_deviation(self, new_sample): if not self.success: return previous_sample = self.load_sample() self.save_sample(new_sample) try: max_deviation = self.options.get_float( self.OPTION_MAX_DEVIATION, None ) except TypeError as e: return if previous_sample is None or new_sample is None: # too little information available -> optimistically assume no deviation deviation = 0 elif previous_sample == "": if new_sample == "": deviation = 0 else: deviation = 100 else: deviation = 100 * len(new_sample) / len(previous_sample) - 100 additional_message = "Deviation in size %f%% (max %f%%)" % ( deviation, max_deviation ) debug(additional_message) self.success &= deviation <= max_deviation self.message += "\n\n" + additional_message
def fill_from_file(self, filename): """ Method loads configuration from file into dictionary. """ debug("filling configuration from '%s'" % filename) fp = open(filename, "r") sections = dict() options = OptionsDict() for line in fp.readlines(): line = line.strip() if line.startswith("#"): continue if line.startswith('[') and line.endswith(']'): options = OptionsDict() sections[line[1:-1].strip()] = options continue if '=' in line: key, value = tuple(line.split("=", 1)) options[key.strip()] = value.strip() continue fp.close() debug("filled configuration is: '%s'" % str(sections)) self.update(sections)
def check(self): """ Executes all checks according to configuration. """ if not self.options.get_bool('check'): debug("check skipped: disabled in configuration") return self._check()
def correct(self, user): home_path = self.get_home_for_user(user) debug("setting permissions for %s to %o" % (home_path, self.permissions)) if not isdir(home_path): debug("...directory does not exist. Doing nothing.") return self.execute_safely(chmod, home_path, self.permissions)
def auto(self): """ Run all actions in the correct order. (Calls this from outside) """ debug("started") self._load_configs() self._load_users() self.do_checks()
def correct(self, user): home_path = self.get_home_for_user(user) debug("setting owner for %s to %s" % (home_path, user.pw_name)) if not isdir(home_path): debug("...directory does not exist. Doing nothing.") return self.execute_safely(chown, home_path, self.owner_uid_for_user(user), -1)
def correct(self, user): home_path = self.get_home_for_user(user) debug("setting permissions for %s to %o" % ( home_path, self.permissions)) if not isdir(home_path): debug("...directory does not exist. Doing nothing.") return self.execute_safely(chmod, home_path, self.permissions)
def is_correct(self, user): home_path = self.get_home_for_user(user) debug("checking directory owner for %s" % user.pw_name) if not isdir(home_path): debug("...directory does not exist. Ignoring.") return True current_uid = self.__class__.owner_uid_for_path(home_path) return current_uid == self.owner_uid_for_user(user)
def get_checks(cls): """ Acquires all checks (classes) in the module 'checks'. """ checks = [ t[1] for t in getmembers(checks_module, isclass) if not t[0].startswith("Abstract") ] debug("found checks: %s" % str([s.__name__ for s in checks])) return checks
def get_checks_sorted(cls): """ Sames as get_checks but checks are sorted, starting with most important. """ checks = cls.get_checks() checks.sort(key=lambda check: check.order) debug("sorted checks: %s" % str([s.__name__ for s in checks])) return checks
def auto(self): """ Run all actions in the correct order to read config and check all targets. """ debug("started in auto mode") self.load_configs() self.test_targets() self.mail_results()
def stop_live(): debug(f"=== rest api:stop_live ===") if 'ffmpeg_process' not in session: return "success" debug(f"kill process: {session['ffmpeg_process']}") # os.killpg(os.getpgid(session['ffmpeg_process']), signal.SIGTERM) # os.killpg(session['ffmpeg_process'], signal.SIGTERM) os.kill(session['ffmpeg_process'], signal.SIGTERM) return "success"
def get_strategies(cls): """ Acquires all strategies (classes) in the module 'strategies'. """ strategies = [ t[1] for t in getmembers(strategies_module, isclass) ] debug("found stategies: %s" % str( [s.__name__ for s in strategies] )) return strategies
def do_checks(self): for check_cls in HomesChecker.get_checks_sorted(): debug("doing check for %s" % str(check_cls)) check = check_cls( self.homes_path, self.users, self.simulate, self.configs[check_cls.config_section] ) check.check()
def stop_live(self): debug(f"=== stop_live ===") if self.init is False: return 404 r = requests.get(url=f'{self.url}/stop_live', cookies=self.session_cookie) # if r.status_code == 200: # with open(path, 'wb') as f: # for chunk in r.iter_content(1024): # f.write(chunk) return r.status_code
def _check(self): """ For every user, check if home correct and correct if required and configured. """ for user in self.users: if not self.is_correct(user): if not self.options.get_bool('correct'): debug("correction skipped: disabled in configuration") continue self.correct(user)
def _check(self): """ For every user, check if the home directory is correct and correct with respect to the configuration. """ for user in self.users: if not self.is_correct(user): if not self.options.get_bool('correct'): debug("correction skipped: disabled in configuration") continue self.correct(user)
def _check(self): """ For every existing home directory, check if it's correct and correct if required and configured. """ for directory in self.get_existing_directories(): if not self.is_correct(directory): if not self.options.get_bool('correct'): debug("correction skipped: disabled in configuration") continue self.correct(directory)
def do_check(self): """ Method coordinates check. """ self._do_request() debug("%sreached\n\n'%s'\n" % ( 'NOT ' if not self.success else '', ''.join([COLOR_LIGHT, self.message, COLOR_STD]) )) self.check_deviation(self.response_str)
def get_frame(self, path=None): debug(f"=== get_frame {path} ===") if self.init is False: return 404 r = requests.get(url=f'{self.url}/get_frame', cookies=self.session_cookie) if r.status_code == 200: if path is not None: with open(path, 'wb') as f: for chunk in r.iter_content(1024): f.write(chunk) return r.status_code
def ping(self, url): debug(f"=== ping ===") r = requests.get(url=f'{url}/', cookies=self.session_cookie) if r.status_code == 200: debug(f"cookies:{r.cookies}") if 'session' in r.cookies: self.session_cookie = {'session': r.cookies['session']} # if r.status_code == 200: # with open(path, 'wb') as f: # for chunk in r.iter_content(1024): # f.write(chunk) return r.status_code
def correct(self, user): home_path = self.get_home_for_user(user) debug("setting owner for %s to %s" % (home_path, user.pw_name)) if not isdir(home_path): debug("...directory does not exist. Doing nothing.") return self.execute_safely( chown, home_path, self.owner_uid_for_user(user), -1 )
def _frame(self, path=None): # example to read file # https://stackoverflow.com/questions/13137817/how-to-download-image-using-requests debug(f"=== _frame ===") if self.init is False: return 404 r = requests.get(url=f'{self.url}/_frame', cookies=self.session_cookie) if r.status_code == 200: if path is not None: with open(path, 'wb') as f: for chunk in r.iter_content(1024): f.write(chunk) return r.status_code
def check_existance_and_fill_missing_files(self, user): """ Does the actual check for ``is_correct`` and stores paths of missing files in ``self.missing_files`` (what ``self.is_correct`` already initialized). """ append_to_missing_files = self.missing_files[user].append for unexpanded_path in self.unexpanded_paths: file_path = self.expand_string_for_user(unexpanded_path, user) if not self.equal_files_for_expanded_path(user, file_path): debug("...not equal.") append_to_missing_files(file_path)
def preprocess_configs(self, configs): """ Method prepares every service in configs for running the tests. """ self._strategies = MeerkatMon.get_strategies() for section, options in configs.items(): debug("processing service '%s'" % section) if section not in ['meerkatmon_default', 'meerkatmon_global']: options.apply_defaults(self.default_configs) options = self.parse_target(section, options) options = self.assign_strategy(section, options) configs[section] = options return configs
def start_live(self, address, timestamp=False, frame_rate=30): debug(f"=== start_live ===") if self.init is False: return 404 r = requests.get( url= f'{self.url}/start_live/{address}/{ 1 if timestamp is True else 0 }/{frame_rate}', cookies=self.session_cookie) # if r.status_code == 200: # with open(path, 'wb') as f: # for chunk in r.iter_content(1024): # f.write(chunk) return r.status_code
def do_checks(self): for check_cls in ChecksRunner.get_checks_sorted(): options = self.configs.get(check_cls.config_section, None) if not options: debug("no configuration for %s! Skipping." % check_cls) continue debug("doing check for %s" % check_cls) check = check_cls(self.home_path, self.users, self.simulate, self.configs[check_cls.config_section]) check.check()
def post_init(self): """ Load file paths from configured file into ``unexpanded_paths``. """ self.missing_files = {} """ Dictionary of {user: file_name} Where ``user`` is an objects in terms of Pythons built-in pwd module and ``file_name`` an expanded path. """ debug("Loaded list of files for section '%s': %r" % (self.config_section, self.unexpanded_paths))
def equal_files_for_expanded_path(self, user, file_path): """ Compares the corresponding file in home and real root. Returns ``True`` if files are egual, ``False`` otherwise. """ src_file_path, dst_file_path = self.get_src_and_dst_path( user, file_path) debug("Comparing '{0}' and '{1}'".format(src_file_path, dst_file_path)) if not isfile(dst_file_path): return False return compare_files(src_file_path, dst_file_path)
def _check(self): """ Checks correctness and corrects if configured using iterables of all users and existing directories. """ directories = list(self.get_existing_directories()) users = self.users if not self.is_correct(users, directories): debug("correction required") if not self.options.get_bool('correct'): debug("correction skipped: disabled in configuration") return self.correct(users, directories)
def _check(self): """ Checks correctness and corrects if configured using iterables of all users and existing directories. """ directories = list(self.get_existing_directories() or []) users = self.users if not self.is_correct(users, directories): debug("correction required") if not self.options.get_bool('correct'): debug("correction skipped: disabled in configuration") return self.correct(users, directories)
def do_checks(self): for check_cls in ChecksRunner.get_checks_sorted(): options = self.configs.get(check_cls.config_section, None) if not options: debug("no configuration for %s! Skipping." % check_cls) continue debug("doing check for %s" % check_cls) check = check_cls( self.home_path, self.users, self.simulate, self.configs[check_cls.config_section] ) check.check()
def check_existance_and_fill_missing_files(self, user): """ Checks if all binaries listed in the configuration and their required libraries are identically present in the home. """ append_to_missing_files = self.missing_files[user].append for unexpanded_path in self.unexpanded_paths: binary_path = self.expand_string_for_user(unexpanded_path, user) dependencies = self.get_dependendencies_for_expanded_path( binary_path) for path in dependencies + [binary_path]: if not self.equal_files_for_expanded_path(user, path): debug("...not equal.") append_to_missing_files(path)
def send_mails(self, headers_and_messages=None): """ Method actually does send an email. """ if not headers_and_messages: return s = SMTP('localhost') for headers, message in headers_and_messages: msg = MIMEText(message) for key, value in headers.items(): msg[key] = value debug("sending %s" % str(msg)) s.sendmail( headers['From'], [r[1] for r in getaddresses([headers['To']])], msg.as_string() ) s.quit()
def assign_strategy(self, section, options): """ Rates all strategies for all targets and selects the best one. """ global_options = self.global_options best_strategy = (None, KNOWLEDGE_NONE) for strategy in self._strategies: strategy_for_target = strategy( global_options, section, options, ) knowledge = strategy_for_target.target_knowledge() if knowledge > best_strategy[1]: best_strategy = (strategy_for_target, knowledge) debug("choosen strategy is '%s'" % best_strategy[0].__class__.__name__) options['strategy'] = best_strategy[0] return options
def get_dependendencies_for_expanded_path(self, binary_path): """ Returns a list of paths to librarires that are required by """ out = [] ldd_out = check_output(['ldd', binary_path]).decode('utf-8') ldd_out_lines = ldd_out.split("\n") for ldd_out_line in ldd_out_lines: # ex:' libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (…)' if '=> /' in ldd_out_line: out.append(ldd_out_line.split(' ')[2]) # ex: " /lib64/ld-linux-x86-64.so.2 (…)" if ldd_out_line.startswith("\t/"): out.append(ldd_out_line.split(" ")[0].strip()) debug("Dependencies for '{0}': {1}".format(binary_path, out)) return out
def send_mails(self, headers_and_messages=None): """ Method actually does send an email. """ if not headers_and_messages: return s = SMTP('localhost') for headers, message in headers_and_messages: msg = MIMEText(message) for key, value in headers.items(): msg[key] = value debug("sending %s" % str(msg)) try: s.sendmail( headers['From'], [r[1] for r in getaddresses([headers['To']])], msg.as_string() ) except ConnectionRefusedError: print("ERROR: could not send emails. " "Connection to localhost refused.") s.quit()
def start_live(address, timestamp, frame_rate): debug(f"=== rest api:get_live at {address}, timestamp: {timestamp} ===") if eval(timestamp) == 1: ffmpeg = "ffmpeg -f {device} -framerate 30 -video_size 1280x720 -i {camera} -vcodec libx264 " \ "-preset ultrafast -tune zerolatency -pix_fmt yuv422p " \ "-vf drawtext=\"fontfile=/System/Library/Fonts/NewYork.ttf: text=\"{text}\": fontcolor=white: fontsize=36: x=(w-text_w)/2: y=(h-text_h)/2\" " \ "-r {rate} -f mpegts udp://{addr}".format(device= config.INPUT_DEVICE, camera=config.CAMERA_ID, text="%\{gmtime\}", rate=frame_rate, addr=address) else: ffmpeg = "ffmpeg -f {device} -framerate 30 -video_size 1280x720 -i {camera} -vcodec libx264 " \ "-preset ultrafast -tune zerolatency -pix_fmt yuv422p " \ "-r {rate} -f mpegts udp://{addr}".format(device=config.INPUT_DEVICE, camera=config.CAMERA_ID, rate=frame_rate, addr=address) # ffmpeg -f avfoundation -framerate 30 -video_size 1280x720 -i "0:none" -vcodec libx264 -preset ultrafast # -tune zerolatency -pix_fmt yuv422p -f mpegts udp://192.168.8.3:12345 # return_code = subprocess.run([ffmpeg], shell=True) # debug(f"=== subprocess.run return {return_code} ===") debug(f"{ffmpeg}") process = subprocess.Popen(ffmpeg, shell=True) debug(f"=== subprocess.Popen return {process.pid} ===") session["ffmpeg_process"] = process.pid debug(f"process: {process.pid}") debug(f"process: {session['ffmpeg_process']}") return "success"
def mail_results_together(self, results): """ Method mails test results all together to global admin. """ mail_from = self.global_options['mail_from'] mail_admin = self.default_configs['admin'] mail_subject = 'Output from checking ' + ', '.join(list(results.keys())) mail_messages_delim = "\n\n%s\n\n" % ("="*80) mail_message = mail_messages_delim.join(( ''.join(("--- ", r['subject'], " ---\n", r['message'])) for r in list(results.values()) )) if not mail_message: debug("Mailing together. Nothing to do.") return mail_headers = { 'From': mail_from, 'To': mail_admin, 'Subject': mail_subject, } self._mail_headers_add_references(mail_headers) debug("Mailing together. Collected %s" % str((mail_headers, mail_message))) self.send_mails([(mail_headers, mail_message)])
def mail_results_separate(self, results): """ Method mails test results all together to admin specified in corresponding section or global admin if absent. """ # list of tuples: (<header dict>, <message str>) headers_and_messages = list() mail_from = self.global_options['mail_from'] for section, result in results.items(): mail_to = self.configs[section]['admin'] mail_subject = result['subject'] mail_message = result['message'] mail_headers = { 'From': mail_from, 'To': mail_to, 'Subject': mail_subject, } self._mail_headers_add_references(mail_headers, section) headers_and_messages.append((mail_headers, mail_message)) debug("mailing separate. Collected %s" % str(headers_and_messages)) self.send_mails(headers_and_messages)
def do_check(self): cmd = [ self.which('ping'), '-W', self.options.get('timeout', '5'), '-c', self.options.get('count', '1'), self.target.netloc ] debug("running command: %s" % str(cmd)) success = True try: output = check_output(cmd, stderr=STDOUT) except CalledProcessError as e: success = False output = e.output self.output = output.decode().strip() self.success = success debug("had %ssuccess \n\n'%s'\n" % ( 'NO ' if not self.success else '', ''.join([COLOR_LIGHT, self.output, COLOR_STD]) ))
def do_trash_directory(self, directory_path): """ Moves directory to trash. """ if listdir(directory_path): debug("archiving directory '%s'" % directory_path) if not self.do_archive_directory(directory_path): return else: debug("not archiving empty directory '%s'" % directory_path) debug("deleting directory '%s'" % directory_path) self.execute_safely(rmtree, directory_path, ignore_errors=True)
def _frame(): debug("=== rest_api:_frame ===") # debug(f"session: {session}") # debug(f"session type: {type(session)}") # if 'test' not in session: # session['test'] = 1 # debug(f"set session[test]={session['test']}") # else: # debug(f"get session[test]={session['test']}") # return "success" if 'frame' not in session: debug(f"no frame found in seesion") return get_frame() # put _frame in response debug(f"put current _frame to response ===") retval, buffer = cv2.imencode('.png', session['frame']) response = make_response(buffer.tobytes()) response.headers.set('Content-Type', 'image/png') # debug(f"return response ===") return response
def do_trash_directory(self, directory_path): """ Moves directory to trash. """ if listdir(directory_path): debug("archiving directory '%s'" % directory_path) if not self.do_archive_directory(directory_path): return else: debug("not archiving empty directory '%s'" % directory_path) debug("deleting directory '%s'" % directory_path) self.execute_safely( rmtree, directory_path, ignore_errors=True)
def RankedPairs(candidates, ballots, ignored_candidates=[], tie_breaker=None): candidates = list(candidates) candidates.sort() tie_breaker_list = [] if tie_breaker: tie_breaker_list = tie_breaker.split('>') if len(set(tie_breaker_list)) != len(tie_breaker_list): raise InvalidTieBreakerException( 'The tie breaker ballot must not contain duplicate candidates') if len(tie_breaker_list) < len(candidates): raise InvalidTieBreakerException( 'The tie breaker ballot must contain all candidates') for cand in tie_breaker_list: if not cand in candidates: raise InvalidTieBreakerException( 'Invalid candidate %s in tie breaker' % (cand)) # Create pairs pairs = {} for i, cand1 in enumerate(candidates): for cand2 in candidates[i + 1:]: pair_name = cand1 + cand2 pair = pairs[pair_name] = { 'diff': 0, 'winner': None, 'loser': None, cand1: 0, cand2: 0 } # Tally blank_ballots = 0 cand_stats = {} for cand in candidates: cand_stats[cand] = {'won': 0, 'lost': 0, 'mentions': 0} for ballot in ballots: already_mentioned = [] rows = ballot.split('>') # Turn blank votes into an empty list rows = list(filter(lambda row: len(row), rows)) rows = list(map(lambda row: row.split('='), rows)) if not len(rows): blank_ballots += 1 continue for y, cur_row in enumerate(rows): for cur_col in cur_row: if not cur_col in candidates: raise InvalidBallotException( 'Invalid candidate %s in ballot %s' % (cur_col, ballot)) if cur_col in already_mentioned: raise InvalidBallotException( 'Duplicate candidate %s in ballot %s' % (cur_col, ballot)) already_mentioned.append(cur_col) cand_stats[cur_col]['mentions'] += 1 # Consider candidates not mentioned as lesser than those mentioned rows.append(list(set(candidates) - set(already_mentioned))) print(rows) for y, cur_row in enumerate(rows): for cur_col in cur_row: for lesser_row in rows[y + 1:]: for lesser_col in lesser_row: if not lesser_col in candidates: raise InvalidBallotException( 'Invalid candidate %s in ballot %s' % (cur_col, ballot)) if lesser_col == cur_col: raise InvalidBallotException( 'Duplicate candidate %s in ballot %s' % (cur_col, ballot)) pair_name = ''.join(sorted((cur_col, lesser_col))) pairs[pair_name][cur_col] += 1 # Check blank vote count debug('%d ballots cast (%d blank)' % (len(ballots), blank_ballots)) if blank_ballots >= len(ballots) / 2: raise TooManyBlankBallotsException('Too many blank ballots', blank_ballots, len(ballots)) # Disqualify candidates as needed disqualified_candidates = [] for cand, stats in cand_stats.items(): is_ignored = cand in ignored_candidates has_insufficient_mentions = stats['mentions'] < len(ballots) / 2 if (is_ignored or has_insufficient_mentions): candidates.remove(cand) for pair_name in dict(pairs): cands = list(pair_name) if cand in cands: del pairs[pair_name] if is_ignored: debug('%s is ignored in this election' % (cand)) elif has_insufficient_mentions: disqualified_candidates.append(cand) debug('%s is disqualified due to insufficient mentions' % (cand)) # Determine the results of the compared pairs for pair_name, pair in pairs.items(): cand1, cand2 = list(pair_name) pair['diff'] = pair[cand1] - pair[cand2] if pair[cand1] > pair[cand2]: cand_stats[cand1]['won'] += 1 cand_stats[cand2]['lost'] += 1 pair['winner'] = cand1 pair['loser'] = cand2 elif pair[cand2] > pair[cand1]: cand_stats[cand2]['won'] += 1 cand_stats[cand1]['lost'] += 1 pair['winner'] = cand2 pair['loser'] = cand1 else: if not tie_breaker: raise TieBreakerNeededException() cand1_index = tie_breaker_list.index(cand1) cand2_index = tie_breaker_list.index(cand2) if cand1_index < cand2_index: cand_stats[cand1]['won'] += 1 cand_stats[cand2]['lost'] += 1 pair['winner'] = cand1 pair['loser'] = cand2 else: cand_stats[cand2]['won'] += 1 cand_stats[cand1]['lost'] += 1 pair['winner'] = cand2 pair['loser'] = cand1 debug('\nCompared pairs:') debug(pairs) debug('\nCandidate pair scores:') debug(cand_stats) # Order the pairs ordered_entries = [] entries = list(pairs.items()) while len(entries): max_diff = -1 max_diff_indices = None for i, pair in enumerate(entries): abs_diff = abs(pair[1]['diff']) if abs_diff > max_diff: max_diff = abs_diff max_diff_indices = [i] elif abs_diff == max_diff: max_diff_indices.append(i) if len(max_diff_indices) == 1: # No tie pair = entries[max_diff_indices[0]] ordered_entries.append(pair) entries.pop(max_diff_indices[0]) else: # We have a tie, follow §2.10 # Obtain the pairs, from the highest index to the lowest as to not mess up the indices when popping max_diff_indices.sort(reverse=True) equal_pairs = [] for i in max_diff_indices: equal_pairs.append(entries[i]) entries.pop(i) # 1. The equal pair with a loser that's already listed as a loser is put first loser_entries = [ ] # All losers that are already in the ordered pairs for i, equal_pair in enumerate(equal_pairs): # Find the loser of the equal pair equal_pair_loser = equal_pair[1]['loser'] # Check if the loser is already in the ordered pairs as a loser ordered_index = None for n, ordered_entry in enumerate(ordered_entries): ordered_loser = ordered_entry[1]['loser'] if equal_pair_loser == ordered_loser: ordered_index = n break if ordered_index is not None: loser_entries.append({'eq_i': i, 'or_i': ordered_index}) loser_entries.sort( reverse=True, key=lambda x: x['or_i']) # Don't mess up indices when popping new_ordered_loser_entries = [] for i, loser_entry in enumerate(loser_entries): next_loser_entry = None try: next_loser_entry = loser_entries[i + 1] except IndexError: pass if next_loser_entry is None or next_loser_entry[ 'or_i'] > loser_entry['or_i']: new_ordered_loser_entries.append(loser_entry['eq_i']) new_ordered_loser_entries.sort( reverse=True) # Don't mess up indices when popping for i in new_ordered_loser_entries: ordered_entries.append(equal_pairs[i]) equal_pairs.pop(i) # 2. The pair with a winner that's already listed as a winner is put first winner_entries = [ ] # All winners that are already in the ordered pairs for i, equal_pair in enumerate(equal_pairs): # Find the winner of the equal pair equal_pair_winner = equal_pair[1]['winner'] # Check if the winner is already in the ordered pairs as a winner ordered_index = None for n, ordered_entry in enumerate(ordered_entries): ordered_winner = ordered_entry[1]['winner'] if equal_pair_winner == ordered_winner: ordered_index = n break if ordered_index is not None: winner_entries.append({'eq_i': i, 'or_i': ordered_index}) winner_entries.sort( reverse=True, key=lambda x: x['or_i']) # Don't mess up indices when popping new_ordered_winner_entries = [] for i, winner_entry in enumerate(winner_entries): next_winner_entry = None try: next_winner_entry = winner_entries[i + 1] except IndexError: pass if next_winner_entry is None or next_winner_entry[ 'or_i'] > winner_entry['or_i']: new_ordered_winner_entries.append(winner_entry['eq_i']) new_ordered_winner_entries.sort( reverse=True) # Don't mess up indices when popping for i in new_ordered_winner_entries: ordered_entries.append(equal_pairs[i]) equal_pairs.pop(i) if len(equal_pairs) > 1: # 3. The pair with a loser that is least preferred by the tie breaker balllot is put first if not tie_breaker: raise TieBreakerNeededException() loser_pref_indices = [] for i, equal_pair_entry in enumerate(equal_pairs): loser = equal_pair_entry[1]['loser'] loser_pref_indices.append({ 'eq_i': i, 'or_i': tie_breaker_list.index(loser) }) new_ordered_tie_breaker_pairs = [] for i, pair in enumerate(loser_pref_indices): next_pair = None try: next_pair = loser_pref_indices[i + 1] except IndexError: pass if (next_pair is None or next_pair['or_i'] > pair['or_i']): new_ordered_tie_breaker_pairs.append(pair['eq_i']) new_ordered_tie_breaker_pairs.sort( reverse=True) # Don't mess up indices when popping for i in new_ordered_tie_breaker_pairs: ordered_entries.append(equal_pairs[i]) equal_pairs.pop(i) # There should only be one pair remaining at this point ordered_entries.extend(equal_pairs) debug('\nRanked pairs') debug(ordered_entries) # Make a graph of the winning pairs lock = {} for cand in candidates: lock[cand] = [] lock_entries = [] debug('\nLock:') for entry in ordered_entries: pair = entry[1] lock[pair['winner']].append(pair['loser']) if is_cyclic(lock): lock[pair['winner']].remove(pair['loser']) continue lock_entries.append((pair['winner'], pair['loser'])) debug('%s → %s' % (pair['winner'], pair['loser'])) # Find the candidate at the root of graph (with nothing pointing to it) possible_winners = list(candidates) cands_pointed_to = set(item for sublist in lock.values() for item in sublist) for cand in cands_pointed_to: possible_winners.remove(cand) winner = possible_winners[0] debug('\nWinner: %s' % (winner)) return { 'ballots': len(ballots), 'blank_ballots': blank_ballots, 'winner': winner, 'disqualified_candidates': disqualified_candidates, 'comp_pairs': pairs, 'ranked_pairs': ordered_entries, 'cand_stats': cand_stats, 'lock': lock_entries, 'graph': lock }
# https://answers.splunk.com/answers/306952/return-binary-data-such-as-images-via-rest-api-or.html # curl examples # https://www.keycdn.com/support/popular-curl-examples if __name__ == "__main__": import os if not os.path.exists('output'): os.makedirs('output') # URL = 'http://localhost:5000' URL = 'http://0.0.0.0:33' cam = Camera() status = cam.allocate_camera(URL) debug(f"response: {status}") status = cam._frame(path='output/_frame.png') debug(f"response: {status}") assert 200 == status status = cam.get_frame(path='output/new_frame.png') debug(f"response: {status}") assert 200 == status status = cam.start_live('127.0.0.1:12345') debug(f"response: {status}") assert 200 == status status = cam.stop_live() debug(f"response: {status}")
def is_correct(self, users, directories): debug("checking for missing directories") return not bool(self.missing_directories(users, directories))
def correct(self, users, directories): for directory in self.missing_directories(users, directories): debug("creating missing directory '%s'" % directory) self.execute_safely(mkdir, directory, mode=700)
def free_camera(self): debug(f"=== free_camera ===") if self.init is True: self.init = False self.url = None return 200