def require(package): """ Specifies a package that should be installed. By default, this method will use the default package manager of the OS (brew for Mac, apt-get for Ubuntu, etc.), but you can override the default package by specifying it in the `package_aliases.py` file. Args: package (str): User-friendly name of package. Most often, this will be the same as the actual name of the package in the package manager, but some packages will have different names on different systems. Use your best judgement to determine what name to use. """ DefaultPackageManager = default_package_managers[get_platform()] command = DefaultPackageManager(package) if package in package_aliases: default = package_aliases[package].get('default', command) command = package_aliases[package].get(get_platform(), default) if command is None: return spinner = Halo(text="Installing {}".format(package), spinner="dots", placement="right") spinner.start() successful = command.execute() if not successful: spinner.fail() else: spinner.succeed()
def find_operator_info(args: argparse.Namespace, operator_name: str) -> None: """With the specified arguments, calls all the functions needed to find information and print all information out to the screen. This function will determine whether to use Gamepress or JSON for information, then call either one's appropriate information-getting functions and build an Operator object using the provided information. The Operator object will be used for printing. Nothing is returned. """ spinner = Halo(text="Fetching...", spinner="dots", color="magenta") # Initialize the arguments for cmd purposes spinner.start() operator_dict, operator_key = get_operator_dict(operator_name) spinner.text = "Parsing..." spinner.color = "yellow" operator = parse_operator_data(args, operator_dict, operator_key, operator_name) # ---------------------------------------- if operator is not None: spinner.succeed("Success!") if operator_dict == {} or args.gamepress: sys.stdout.write("\nSkipping JSON; Using gamepress.\n") # Print out the results sys.stdout.write("\n\n" + operator.name + " ") sys.stdout.write("*" * operator.rarity + " ") # Star rarity sys.stdout.write(operator.profession + "\n") sys.stdout.write(operator.get_formatted_tags() + "\n\n") for desc_text in operator.description: sys.stdout.write(desc_text) all_properties = [ operator.get_property(prop) for prop in operator.get_all_properties() ] # Fetch the stats all_messages = ([parse_stats(operator.stats)] + all_properties if (operator.has_stats()) else all_properties) for prop in all_messages: for text in prop: sys.stdout.write(text + "\n") else: spinner.fail("Failed.") sys.stdout.write("\n\n" + operator_name.replace("-", " ").title() + "\n") sys.stdout.write("\n" + "Could not find operator! " + "Either the server is down, or your spelling is! \n") sys.stdout.write("\n\n")
def list_tag_shortcuts(args: argparse.Namespace) -> None: """Retrieves the shortcut-tag information and formats it in a specified way. Returns nothing as it prints out directly to the display. Formats based on whether `args.reverse` is True or not by calling a separate function that will independantly fetch the proper information in the formatted and correct way. (ie. either (tags -> shortcuts) or (shortcuts -> tags)). """ spinner = Halo(text="Searching...", spinner="dots", color="blue") spinner.start() # Call the appropriate function to get the appropriate info if args.reverse: succeeded, messages = list_reversed_tag_shortcuts(args) else: succeeded, messages = list_proper_tag_shortcuts(args) # Succeeded flag lets us know whether to fail the spinner or not # in an easier to understand and less scuffed way. # TODO: this seems scuffed but slightly less so if succeeded: spinner.succeed("Success!") else: spinner.fail("Failed.") # Write all the stored messages # spinner.succeed("Success!") for message in messages: sys.stdout.write(message + "\n") sys.stdout.write("\n") # padding for formatting
def getAuthInfo(): # cacheが存在する場合 if os.path.exists(const.CACHE_FILE): cache = util.getCache() # 期限OK if cache.deadline > time.time(): authInfo = cache.auth # 期限NG else: spinner = Halo(text=const.MSG_REQUEST_TOKEN, spinner='dots') spinner.start() try: authInfo = authorize() except Exception: spinner.fail() raise exception.AuthorizeError(const.MSG_AUTHORIZE_ERROR) else: spinner.succeed() else: spinner = Halo(text=const.MSG_REQUEST_TOKEN, spinner='dots') spinner.start() try: authInfo = authorize() except Exception: spinner.fail() raise exception.AuthorizeError(const.MSG_AUTHORIZE_ERROR) else: spinner.succeed() return authInfo
class HaloFeedback(Feedback): def __init__(self, message=None): self.spinner = Halo(text=message or '', spinner='dots') if message and not default_config.debug: self.spinner.start() def update_message(self, message): super().update_message(message) if not self.spinner._spinner_id and not default_config.debug: self.spinner.start() self.spinner.text = (message + ' ...') if self.message else '' def succeeded(self): self.spinner.text = self.message self.spinner.succeed() def errored(self, error): # self.spinner.text = str(error) if error else self.message self.spinner.text = f'{self.message} ... {colored(str(error), "red")}' self.spinner.fail() sys.exit(1) def warning(self, warning): self.spinner.text = f'{self.message} ... {colored(str(warning), "yellow")}' self.spinner.warn() def info(self, message): self.spinner.info(message) def exists(self, error): self.warning('exists')
def _echo_pending_tx_info(self, tx_hash: str, title: str = '') -> bool: spinner = Halo(text="Checking transaction status...", spinner='dots') spinner.start() tx_info = dict() for _ in range(5): try: time.sleep(6) tx_info = self.ontology.rpc.get_transaction_by_tx_hash(tx_hash) break except SDKException: continue if len(tx_info) == 0: spinner.fail() echo( f"Using 'punica info status {tx_hash}' to query transaction status." ) return False spinner.succeed() payer = tx_info.get('Payer', '') balance = self.ontology.rpc.get_balance(payer) echo('') if len(title) != 0: echo(title) echo('-' * len(title)) echo(f'> transaction hash: {tx_hash}') echo(f"> block height: {tx_info.get('Height', '')}") echo(f"> nonce: {tx_info.get('Nonce', '')}") echo(f"> gas price: {tx_info.get('GasPrice', '')}") echo(f"> gas limit: {tx_info.get('GasLimit', '')}") echo(f"> payer: {payer}") echo( f"> balance: {balance['ONT']} ONT, {balance['ONG'] * (10 ** -9)} ONG\n" ) echo('> Saving transaction to chain.\n') return True
def run_execute(text, cmd, cwd=None, status_check="OK"): global args if args.verbose: spinner = Halo(text=text, spinner='dots') spinner.start() start = timeit.default_timer() res = subprocess.call(cmd, cwd=cwd, stdout=None, stderr=None, shell=True) end = round(timeit.default_timer() - start, 3) if args.verbose: if status_check == "OK": status_text = f'{text} -> {end}sec' if args.verbose: status_text = f'{text} , {cmd} -> {end}sec' if res != 0: spinner.fail(bcolors.FAIL + status_text + bcolors.ENDC) cprint(f"[FAIL] {text}", "red") sys.exit(1) else: status_header = bcolors.WARNING + "[DONE]" + bcolors.ENDC spinner.succeed(f'{status_header} {status_text}') else: spinner.succeed(f'[SUCCEED] {text} -> {end}sec') else: if res != 0: cprint(f"[FAIL] {text}", "red") subprocess.call(cmd, stdout=None, stderr=None, shell=True) return res
def _refresh_token(self, token_data: Union[dict, List[dict]] = []) -> bool: auth = self.auth token_data = utils.listify(token_data) token = None spin = Halo("Attempting to Refresh Token") spin.start() for idx, t in enumerate(token_data): try: if idx == 1: spin.fail() spin.text = spin.text + " retry" spin.start() token = auth.refreshToken(t) if token: auth.storeToken(token) auth.central_info["token"] = token break except Exception as e: log.exception( f"Attempt to refresh token returned {e.__class__.__name__} {e}" ) if token: self.headers[ "authorization"] = f"Bearer {self.auth.central_info['token']['access_token']}" # spin.succeed() spin.stop() else: spin.fail() return token is not None
def get(name, filter): ''' To get the secrets from keyvault ''' if filter: filter = '*{}*'.format(filter) spinner = Halo( text=colorama.Fore.GREEN + 'Getting list of Secrets which matches the pattern {} ..'.format( filter), spinner='dots', color='yellow') else: spinner = Halo( text=colorama.Fore.GREEN + 'Getting complete list of Secrets for {} ..'.format(name), spinner='dots', color='yellow') spinner.start() if _isExist(name): getSecrets(spinner, name, filter) else: spinner.fail(colorama.Fore.RED + '{} not a valid Azure Key Vault'.format(name))
def register(): # create user user = raw_input("Enter your username:"******"This username exists!\nEnter your username:"******"Password for " + user + ":") password_again = getpass.getpass("Password for " + user + " again:") if(password == password_again): break else: print("The passwords you entered aren't the same!") # hashing password password = MyCrypto().hash_password(password) # create json data = dict([("user", user), ("password", password), ("web_data", [])]) # insert in my db try: x = Halo().start('Creating user') db.insert_user(data) x.succeed(user + 'created!') except: x.fail("Error on insert, try again.") time.sleep(1.5)
def login(): """Authorize access to your Unsplash account. Obtain an access token to interact with protected resources. Access tokens are granted through the standard OAuth authorization code workflow. The authorization web page will be opened automatically in your default web browser. """ spinner = Halo(text="Waiting for authorization...", spinner="dots") spinner.start() auth_url = "%s?client_id=%s&redirect_uri=%s&response_type=code&scope=%s" % ( AUTH, config["access_key"], urllib.parse.quote(config["redirect_uri"]), "+".join(SCOPES), ) click.launch(auth_url) parse = urllib.parse.urlparse(config["redirect_uri"]) server = OAuthServer((parse.hostname, parse.port), RequestHandler) server.serve_forever() if server.auth_success: user = api.current_user() spinner.succeed("Logged in as @%s" % user["username"]) else: spinner.fail("Failed to log into Unsplash. Please try again.")
def get_audience_id(): print('\nCreate Audience:') spinner = Halo(text='Creating audience', spinner='dots') spinner.start() values = { 'name': audience.name, 'description': audience.description, 'subtype': 'CUSTOM', 'customer_file_source': 'USER_PROVIDED_ONLY', 'access_token': access_token } data = urllib.parse.urlencode(values) data = data.encode('ascii') try: with urlopen( "https://graph.facebook.com/v3.2/act_" + account_id + "/customaudiences", data) as response: info = response.read().decode('ASCII') spinner.succeed("Audience was created") response_data = json.loads(str(info)) except HTTPError as e: spinner.fail("Audience creation failed") response = e.read() print(response) sys.exit(-1) return response_data['id']
def qmapflatten(self, dl): spinner = Halo(text='Flattening the survey datamap...', spinner='dots') try: out = "\t".join(['question_group', 'question_label', 'question_title', 'col_title', 'row_title', 'question_type', 'val_key', 'val_title']) + "\n" for a in dl['variables']: out_tmp = '' question_group = self.clean_string(a['vgroup']) question_label = self.clean_string(a['label']) question_title = self.clean_string(a['qtitle']) col_title = self.clean_string(a['colTitle']) row_title = self.clean_string(a['rowTitle']) question_type = self.clean_string(a['type']) default = '' question_values = self.clean_string(a.get('values', default)) val_key = '' val_title = '' if len(question_values) >= 1: for b in question_values: val_key = self.clean_string(str(b['value'])) val_title = self.clean_string(str(b['title'])) out += '\t'.join([question_group, question_label, question_title, col_title, row_title, question_type, val_key, val_title]) + '\n' else: out += '\t'.join([question_group, question_label, question_title, col_title, row_title, question_type, val_key, val_title]) + '\n' spinner.succeed('Completed flattening data') return out except: spinner.fail('An error occured')
def main(): print_banner() p = PrimeAPI() spinner = Halo(spinner='dots') db = create_engine('sqlite:///techxdb.db') Base.metadata.create_all(db) Base.metadata.bind = db DBSession = sessionmaker(bind=db) dbs = DBSession() #Process Data spinner.start(text='Processing Data...') devices = DataCollector(p, dbs) time.sleep(5) spinner.succeed(text='Data Collected') #Send Message for bot Request = True spinner.start(text='Sending Notification...') try: response = SparkNotifier(dbs) logger.info('Notification sent') logger.info('Process Completed') spinner.suceed(text='Notification sended') spinner.suceed(text='Process completed') except Exception as e: logger.error('Notification Fails message: {}'.format(e)) spinner.fail(text='Notification failed') response = {"status_code": 500} return response
def handle(self, *args, **options): spinner = Halo(text="Creating super user..", text_color="yellow", spinner="dots") spinner.start() time.sleep(3) admin_url = f"http://127.0.0.1:8000/{settings.ADMIN_URL}" default_password = "******" default_username = "******" try: user = User.objects.create_user( username=default_username, password=default_password, first_name="John", last_name="Doe", is_superuser=True, is_staff=True, email="*****@*****.**", ) spinner.succeed(crayons.green("Success!")) print( crayons.normal( f"ℹ Username: {crayons.yellow(default_username)} - Password: {crayons.yellow(default_password)} - Connect to: {crayons.yellow(admin_url)} \n" )) except IntegrityError: spinner.fail( crayons.red( "The superuser has already been created! use command: 'python manage.py createsuperuser'" ))
def require(package): """ Specifies a package that should be installed. By default, this method will use the default package manager of the OS (brew for Mac, apt-get for Ubuntu, etc.), but you can override the default package by specifying it in the `package_aliases.py` file. Args: package (str): User-friendly name of package. Most often, this will be the same as the actual name of the package in the package manager, but some packages will have different names on different systems. Use your best judgement to determine what name to use. """ DefaultPackageManager = default_package_managers[get_platform()] command = DefaultPackageManager(package) if package in package_aliases: default = package_aliases[package].get('default', command) command = package_aliases[package].get(get_platform(), default) if command is None: return spinner = Halo( text="Installing {}".format(package), spinner="dots", placement="right" ) spinner.start() successful = command.execute() if not successful: spinner.fail() else: spinner.succeed()
def compile_contract(self, contract_name: str): title = contract_name.replace('.py', '') echo(title) echo('-' * len(title)) contract_path, avm_save_path = self.prepare_to_compile(contract_name) compile_spinner = Halo(text=f"Compiling {contract_name}", spinner='bouncingBar') compile_spinner.start() avm_code = self.compile_py_contract_in_remote(contract_path) if len(avm_code) == 0: compile_spinner.fail() return False compile_spinner.succeed() save_spinner = Halo(text=f'Saving avm file...') save_spinner.start() try: save_avm_file(avm_code, avm_save_path) except PunicaException as e: save_spinner.fail() echo(e.args[1]) return False save_spinner.succeed() end_msg = f'> Avm file written to {path.split(avm_save_path)[0]}' echo(''.join(['-' * len(end_msg)])) echo(f'{end_msg}\n') return True
def main(): print_banner() args = get_args() spinner = Halo(spinner='dots') try: spinner.start(text='Parsing configuration file') config = ConfParse() spinner.succeed() except Exception as e: spinner.fail() print("\n\nError parsing configuration file: {}\n".format(e)) exit(1) try: spinner.start(text="Retrieving hpHosts feed: {}".format(args.c)) hphosts_feed = HpHostsFeed(args.c) spinner.succeed() except Exception as e: spinner.fail() print("\n\nError retrieving hpHosts feed: {}\n".format(e)) exit(1) # Create object and load in the retrieved values from above report_filename = "hpHosts-{}-{}".format(args.c, args.o) report = Report(hphosts_feed, report_filename, config) # Process results print("\nProcessing {} entries, this may take a while:\n".format(args.n)) report.write_results(args.n) print("\nGreat success.\n") # Plot stats histogram report.print_stats_diagram(args.n) print("\nDetailed report is available in {}\n".format(report_filename))
def remap_key(src, dest): """ Remaps src key to dest key. An example of remapping the caps lock key to act like the left control key would be to call `remap_key('capslock', 'left-ctrl') Args: src (str): Key name in keyboard dict. This is the key that will change functionality. dest (str): Key name in keyboard dict. The key defined in `src` should act like this key. """ # TODO (phillip): Right now, these changes do not survive a reboot. I am # going to just change this manually in the keyboard settings, but I might # be able to figure out how to do it with `defaults`. # https://apple.stackexchange.com/questions/141069/updating-modifier-keys-from-the-command-line-takes-no-effect spinner = Halo(text="Remapping {} to {}".format(src, dest), spinner="dots", placement="right") spinner.start() remap_dict = { 'UserKeyMapping': [{ 'HIDKeyboardModifierMappingSrc': keyboard[src], 'HIDKeyboardModifierMappingDst': keyboard[dest] }] } try: sh.hidutil("property", "--set", str(remap_dict).replace("'", '"')) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error("Error with `hidutil property --set %s : %s", str(remap_dict), err_message) spinner.fail()
def create_website(): # create website password_acc = get_password() website_name = raw_input("Website name:") while True: password = getpass.getpass("Password for " + website_name + ":") password_again = getpass.getpass( "Password for " + website_name + " again:") if(password == password_again): break else: print("The passwords you entered aren't the same!") # encrypt password password = MyCrypto().encrypt(password, password_acc) # convert to hex password = password.encode('hex') # create json logged_user["web_data"].append( {"website": website_name, "password": password}) # insert in my db try: x = Halo().start('Creating website...') db.insert_website(logged_user) x.succeed("Website " + website_name + " added!") except: x.fail("Error on insert, try again.") time.sleep(1)
def unshorten_adfly_url(self, adfly_url: str): spinner = Halo(text='Grabbing url...', spinner='dots') spinner.start(text='Getting url...') current_link = adfly_url while True: try: url = self.unshorten.unshorten(uri=current_link) current_link = url if 'adfly' in url: pass else: request = self.session.get(url=url) soup = BeautifulSoup(request.text, 'html.parser') if 'redirecting' in request.url: current_link = soup.find_all('p')[2].text.replace('You will be visiting: ', '') spinner.succeed(text='Successfully retrieved url!') return current_link except (InvalidURL, MissingSchema, ConnectionError, NotFound, UnshortenFailed) as exception: spinner.fail(text=f'Error: {exception}') return
class StatusUpdate(object): def __init__(self, title): if sys.stdout.isatty(): self.spinner = Halo(title, spinner='dots') self.spinner.start() else: self.spinner = None print(title) def complete(self, success, message): if self.spinner: if success is True: self.spinner.succeed(message) elif success is False: self.spinner.fail(message) else: self.spinner.warn(message) self.spinner.stop() else: if success is True: print("success: ", message) elif success is False: print("failed: ", message) else: print("warning: ", message)
def ebayItemIdList(make, listLength=None): api = finding(siteid='EBAY-MOTOR', domain='svcs.ebay.com', warnings=True) dictFinding = ({ 'categoryId': '6001', 'aspectFilter': { 'aspectName': 'Make', 'aspectValueName': make }, 'paginationInput': { 'pageNumber': '1', 'entriesPerPage': '100' }, 'paginationOutput': 'totalPages,totalEntries', 'sortOrder': 'PricePlusShippingHighest' }) try: listItemId = [] totalPages = getTotalPages(api, make) spinner = Halo(text='grabbing list of Item IDs', spinner='monkey') spinner.start() for x in range(1, totalPages + 1): dictFinding['paginationInput']['pageNumber'] = str(x) response = json.loads( '%s' % api.execute('findItemsAdvanced', dictFinding).json()) for listing in response['searchResult']['item']: listItemId.append(listing['itemId']) print("\nTOTAL NUMBER OF LISTINGS FOR %s: " % make, len(listItemId)) if listLength != None: spinner.succeed("Returning %s number of Item Ids" % listLength) return listItemId[0:listLength] spinner.succeed("Returning all Item Ids") return listItemId except Exception as e: spinner.fail("ERROR: %s" % e)
def dfload(df_filepath, *args, show_progress=False, parquet_convert_ndarray_to_list=False, **kwargs): '''Loads a dataframe file based on the file's extension. Parameters ---------- df_filepath : str local path to an existing dataframe. The file extension is used to determine the file type. show_progress : bool show a progress spinner in the terminal parquet_convert_ndarray_to_list : bool whether or not to convert 1D ndarrays in the loaded parquet table into Python lists args : list list of positional arguments to pass to the corresponding reader kwargs : dict dictionary of keyword arguments to pass to the corresponding reader Returns ------- pandas.DataFrame loaded dataframe Notes ----- For '.csv' or '.csv.zip' files, we use :func:`mt.pandas.csv.read_csv`. For '.parquet' files, we use :func:`pandas.read_parquet`. Raises ------ TypeError if file type is unknown ''' path = df_filepath.lower() if path.endswith('.parquet'): spinner = Halo("dfloading '{}'".format(path), spinner='dots') if show_progress else dummy_scope with spinner: try: df = _pd.read_parquet(df_filepath, *args, **kwargs) if parquet_convert_ndarray_to_list: for x in df.columns: if show_progress: spinner.text = 'converting column: {}'.format(x) if df.dtypes[x] == _np.dtype('O'): # object df[x] = df[x].apply(array2list) # because Parquet would save lists into nested numpy arrays which is not we expect yet. if show_progress: spinner.succeed("dfloaded '{}'".format(path)) except: if show_progress: spinner.fail("failed to dfload '{}'".format(path)) raise return df if path.endswith('.csv') or path.endswith('.csv.zip'): return read_csv(df_filepath, *args, show_progress=show_progress, **kwargs) raise TypeError("Unknown file type: '{}'".format(df_filepath))
def dfsave(df, df_filepath, file_mode=0o664, show_progress=False, **kwargs): '''Saves a dataframe to a file based on the file's extension. Parameters ---------- df : pandas.DataFrame a dataframe df_filepath : str local path to an existing dataframe. The file extension is used to determine the file type. file_mode : int file mode to be set to using :func:`os.chmod`. If None is given, no setting of file mode will happen. show_progress : bool show a progress spinner in the terminal kwargs : dict dictionary of keyword arguments to pass to the corresponding writer Returns ------- object whatever the corresponding writer returns Notes ----- For '.csv' or '.csv.zip' files, we use :func:`mt.pandas.csv.to_csv`. For '.parquet' files, we use :func:`pandas.DataFrame.to_parquet`. Raises ------ TypeError if file type is unknown or if the input is not a dataframe ''' if not isinstance(df, _pd.DataFrame): raise TypeError("Input must be a pandas.DataFrame. Got '{}'.".format(type(df))) path = df_filepath.lower() if path.endswith('.parquet'): spinner = Halo(text="dfsaving '{}'".format(path), spinner='dots') if show_progress else dummy_scope with spinner: try: if not 'use_deprecated_int96_timestamps' in kwargs: kwargs = kwargs.copy() kwargs['use_deprecated_int96_timestamps'] = True # to avoid exception pyarrow.lib.ArrowInvalid: Casting from timestamp[ns] to timestamp[ms] would lose data: XXXXXXX res = df.to_parquet(df_filepath, **kwargs) if file_mode: # chmod _p.chmod(df_filepath, file_mode) if show_progress: spinner.succeed("dfsaved '{}'".format(path)) except: if show_progress: spinner.fail("failed to dfsave '{}'".format(path)) raise return res if path.endswith('.csv') or path.endswith('.csv.zip'): return to_csv(df, df_filepath, file_mode=file_mode, show_progress=show_progress, **kwargs) raise TypeError("Unknown file type: '{}'".format(df_filepath))
def scan(self, camera_type, url_scheme = '', check_empty_url='',check_empty = True, tag=True, search_q="webcams"): if url_scheme == '': url_scheme = self.default_url_scheme if self.SHODAN_API_KEY == '': print("[red]Please set up shodan API key in environ![/red]") return spinner = Halo(text='Looking for possible servers...', spinner='dots') spinner.start() if tag and (not self.clarifai_initialized): self.init_clarifai() try: results = self.api.search(search_q) spinner.succeed("Done") except: spinner.fail("Get data from API failed") return max_time = len(results["matches"])*10 print(f"maximum time:{max_time} seconds") camera_type_list = [] for result in results["matches"]: if camera_type in result["data"]: camera_type_list.append(result) cnt = 0 for result in camera_type_list: url = f"http://{result['ip_str']}:{result['port']}" cnt+=1 print(f"{cnt}/{len(camera_type_list)}") try: r = requests.get(url, timeout=5) if r.status_code == 200: if check_empty == False: print( url_scheme.format(ip=result['ip_str'], port=result['port']) ) else: is_empty = self.check_empty(check_empty_url.format(url=url)) if is_empty: print( url_scheme.format(ip=result['ip_str'], port=result['port']) ) else: spinner.close() continue if tag: tags = self.tag_image(check_empty_url.format(url=url)) for t in tags: print(f"|[green]{t}[/green]|",end=" ") if len(tags)==0: print("[i green]no description[i green]",end="") print() spinner.close() else: print("[red]webcam not avaliable[/red]") except KeyboardInterrupt: print("[red]terminating...") break except: continue
def spinner(spin_txt: str, function: callable, url: str = None, *args, name: str = None, spinner: str = "dots", debug: bool = False, **kwargs) -> Any: name = name or spin_txt.replace(" ", "_").rstrip(".").lower() if not name.startswith("spinner_"): name = f"spinner_{name}" spin = None if sys.stdin.isatty(): # If a spinner is already running, update that spinner vs creating new active_spinners = [ t for t in threading.enumerate()[::-1] if t.name.startswith("spinner") ] if active_spinners: spin = active_spinners[0]._target.__self__ if debug: spin.stop() else: log.warning( f"A Spinner was already running '{spin.text}' updating to '{spin_txt}'" ) spin.text == spin_txt spin.spinner == "dots12" if spin.spinner == spinner else spinner elif not debug: spin = Halo(text=spin_txt, spinner=spinner) spin.start() threading.enumerate()[-1].name = spin._spinner_id = name if url: args = (url, *args) r = function(*args, **kwargs) if spin: # determine pass if request successful _spin_fail_msg = spin_txt ok = None if hasattr(r, "ok"): ok = r.ok if "refreshToken" in str(function): ok = r is not None if hasattr(r, "json"): _spin_fail_msg = f"spin_text\n {r.json().get('error_description', spin_txt)}" if ok is True: spin.succeed() elif ok is False: spin.fail(_spin_fail_msg) else: spin.stop_and_persist() return r
def wait_for_dcos( cluster: Cluster, superuser_username: str, superuser_password: str, http_checks: bool, doctor_command_name: str, enable_spinner: bool, ) -> None: """ Wait for DC/OS to start. Args: cluster: The cluster to wait for. superuser_username: If the cluster is a DC/OS Enterprise cluster, use this username to wait for DC/OS. superuser_password: If the cluster is a DC/OS Enterprise cluster, use this password to wait for DC/OS. http_checks: Whether or not to wait for checks which require an HTTP connection to the cluster. doctor_command_name: A ``doctor`` command to advise a user to use. enable_spinner: Whether to enable the spinner animation. """ message = ( 'A cluster may take some time to be ready.\n' 'The amount of time it takes to start a cluster depends on a variety ' 'of factors.\n' 'If you are concerned that this is hanging, try ' '"{doctor_command_name}" to diagnose common issues.').format( doctor_command_name=doctor_command_name) click.echo(message) no_login_message = ('If you cancel this command while it is running, ' 'you may not be able to log in. ' 'To resolve that, run this command again.') spinner = Halo(enabled=enable_spinner) spinner.start(text='Waiting for DC/OS variant') _wait_for_variant(cluster=cluster) dcos_variant = get_cluster_variant(cluster=cluster) spinner.succeed() if dcos_variant == DCOSVariant.OSS: click.echo(no_login_message) spinner.start(text='Waiting for DC/OS to start') try: if dcos_variant == DCOSVariant.ENTERPRISE: cluster.wait_for_dcos_ee( superuser_username=superuser_username, superuser_password=superuser_password, http_checks=http_checks, ) else: cluster.wait_for_dcos_oss(http_checks=http_checks) except DCOSTimeoutError: spinner.fail(text='Waiting for DC/OS to start timed out.') sys.exit(1) spinner.succeed()
def get_users(self): spinner = Halo(text='Downloading user data...', spinner='dots') spinner.start() try: result = api.get('rh/users', sort="-last_login", limit="10", select="login,last_login,active") spinner.succeed('User data downloaded') return result except: spinner.fail('User data download failure')
def get_surveys(self): spinner = Halo(text='Downloading survey list...', spinner='dots') spinner.start() try: result = api.get('rh/companies/all/surveys') spinner.succeed('Survey list downloaded') return result except: spinner.fail('An error occured')
def handle_bulk_task(self, task_uuid, retrieve_bulk_result_url, *, timeout, additional_checks: List[Check] = None) \ -> Json: """ Handle a generic bulk task, blocking until the task is done or the timeout is up :param task_uuid: uuid of the bulk task :param retrieve_bulk_result_url: endpoint to query, must contained a task_uuid field :param timeout: timeout after which a TimeoutError is raised :param additional_checks: functions to call on a potential json, if all checks return True, the Json is returned :return: a Json returned on HTTP 200 validating all additional_checks """ retrieve_bulk_result_url = retrieve_bulk_result_url.format( task_uuid=task_uuid) spinner = None if logger.isEnabledFor(logging.INFO): spinner = Halo(text=f'Waiting for bulk task {task_uuid} response', spinner='dots') spinner.start() start_time = time() back_off_time = 1 json_response = None while not json_response: headers = {'Authorization': self.token_manager.access_token} response = requests.get(url=retrieve_bulk_result_url, headers=headers, verify=self.requests_ssl_verify) if response.status_code == 200: potential_json_response = response.json() if additional_checks and not all( check(potential_json_response) for check in additional_checks): continue # the json isn't valid if spinner: spinner.succeed(f'bulk task {task_uuid} done') json_response = potential_json_response elif response.status_code == 401: logger.debug('Refreshing expired Token') self.token_manager.process_auth_error( response.json().get('messages')) elif time() - start_time + back_off_time < timeout: sleep(back_off_time) back_off_time = min(back_off_time * 2, self.OCD_DTL_MAX_BACK_OFF_TIME) else: if spinner: spinner.fail(f'bulk task {task_uuid} timeout') logger.error() raise TimeoutError( f'No bulk result after waiting {timeout / 60:.0f} mins\n' f'task_uuid: "{task_uuid}"') if spinner: spinner.stop() return json_response
def install_homebrew(): """ Installs or upgrades homebrew on mac. If homebrew is not installed, this command will install it, otherwise it will update homebrew to the latest version. Additionally, it will offer to upgrade all homebrew packages. Upgrading all packages can take a long time, so the user is given the choice to skip the upgrade. """ print("Checking homebrew install") if sh.which("brew"): spinner = Halo( text="Updating homebrew", spinner="dots", placement="right" ) spinner.start() sh.brew("update") spinner.succeed() print( "Before using homebrew to install packages, we can upgrade " "any outdated packages." ) response = user_input("Run brew upgrade? [y|N] ") if response[0].lower() == "y": spinner = Halo( text="Upgrade brew packages", spinner="dots", placement="right" ) spinner.start() sh.brew("upgrade") spinner.succeed() else: print("Skipped brew package upgrades") else: # TODO (phillip): Currently, this homebrew installation does not work on a fresh # computer. It works from the command line, but not when run from the script. I # need to figure out what is going on. It could be because user input is needed. spinner = Halo( text="Installing homebrew", spinner="dots", placement="right" ) spinner.start() try: script = sh.curl("-fsSL", BREW_GITHUB).stdout sh.ruby("-e", script) spinner.succeed() except sh.ErrorReturnCode: logging.error("Unable to install homebrew. Aborting...") spinner.fail() exit(1)
def configure(namespace, key, *values): """ Sets configuration on mac using `defaults` """ spinner = Halo( text="Setting {}".format(key), spinner="dots", placement="right" ) spinner.start() try: if namespace: sh.defaults("write", namespace, key, *values) else: sh.defaults("write", key, *values) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error with `defaults write -g %s %s: %s", key, values, err_message ) spinner.fail()
def default_shell(name): """ Sets default shell for the current user. """ spinner = Halo( text="Default shell `{}`".format(name), spinner="dots", placement="right" ) spinner.start() try: path = sh.which(name).strip() user = sh.whoami().strip() with Authentication(): sh.chsh("-s", path, user) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error changing default shell to %s: %s", name, err_message ) spinner.fail()
def remap_key(src, dest): """ Remaps src key to dest key. An example of remapping the caps lock key to act like the left control key would be to call `remap_key('capslock', 'left-ctrl') Args: src (str): Key name in keyboard dict. This is the key that will change functionality. dest (str): Key name in keyboard dict. The key defined in `src` should act like this key. """ # TODO (phillip): Right now, these changes do not survive a reboot. I am # going to just change this manually in the keyboard settings, but I might # be able to figure out how to do it with `defaults`. # https://apple.stackexchange.com/questions/141069/updating-modifier-keys-from-the-command-line-takes-no-effect spinner = Halo( text="Remapping {} to {}".format(src, dest), spinner="dots", placement="right" ) spinner.start() remap_dict = { 'UserKeyMapping': [ { 'HIDKeyboardModifierMappingSrc': keyboard[src], 'HIDKeyboardModifierMappingDst': keyboard[dest] } ] } try: sh.hidutil("property", "--set", str(remap_dict).replace("'", '"')) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error with `hidutil property --set %s : %s", str(remap_dict), err_message ) spinner.fail()
def curl(src, dest): """ Installs `src` to path `dest` """ spinner = Halo( text="curl {}".format(dest), spinner="dots", placement="right" ) spinner.start() if os.path.exists(dest): spinner.info("{} already exists".format(dest)) return try: sh.curl("-fLo", dest, src) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error downloading file `%s`: %s", src, err_message ) spinner.fail()
def extract(src, dest): """ Extracts the source file in dest """ spinner = Halo( text="extract {}".format(src), spinner="dots", placement="right" ) spinner.start() try: # TODO (phillip): This should choose the correct decompression based # on the filename where possible. with tarfile.open(src, "r:gz") as tar: tar.extractall(dest) sh.rm(src) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error extracting file `%s`: %s", src, err_message ) spinner.fail()
def font(name): """ Installs fonts using curl. Args: name (str): The name of the font as defined in `font_library` dictionary. """ spinner = Halo( text="Font {}".format(name), spinner="dots", placement="right" ) spinner.start() try: library = os.path.join(HOME, "Library/Fonts") path = os.path.join(library, name) sh.curl("-fLo", path, font_library[name]) spinner.succeed() except sh.ErrorReturnCode as err: err_message = "\n\t" + err.stderr.replace("\n", "\n\t") logging.error( "Error installing font `%s`: %s", name, err_message ) spinner.fail()
def file(path, template_file, load_vars=lambda: {}): """ Installs a template file using symlinks. If a file already exists at the specified path and it is not a symbolic link, then this function will print an error and return. If the file is a symlink to the `build` directory of your dotfiles repo, then this will check to see if the template has been modified since the file was last built. Args: path (str): Filesystem path where we should install the filled out template file. template_file (str): The filename of the template to install. The file should be located in the $ROOT/templates directory of this repository. load_vars (func): A function that will be run when the file is built to fill in template information. This is passed in as a function so that user input is only asked for when the file is built. """ spinner = Halo(text=path, spinner="dots", placement="right") spinner.start() if os.path.exists(path) and not os.path.islink(path): print("Error: {} exists and is not a soft link".format(path)) spinner.fail() return try: # Load template as a Jinja2 Template template_path = os.path.join( ROOT, os.path.join("templates", template_file) ) template_mtime = os.path.getmtime(template_path) with open(template_path, "r") as template_file: template = Template(template_file.read()) build_path = os.path.join( ROOT, os.path.join("build", os.path.basename(path)) ) if not os.path.exists(build_path): build_mtime = 0 else: build_mtime = os.path.getmtime(build_path) # Build the template if the template has been modified since last build if template_mtime > build_mtime: # TODO (plemons): I should only do this if I actually need user # input. Theoretically, the load_vars function could just read # from a config file making this unnecessary spinner.info("Asking for user input for {}".format(path)) if not os.path.exists(os.path.dirname(build_path)): os.makedirs(os.path.dirname(build_path)) with open(build_path, 'w') as outfile: outfile.write(template.render(**load_vars())) path = os.path.expanduser(path) dirpath = os.path.dirname(path) if not os.path.exists(dirpath): os.makedirs(dirpath) if os.path.islink(path): os.unlink(path) os.symlink(build_path, path) spinner.succeed() except OSError as err: print(err) spinner.fail()