def check_anonymous(self): # If there's no API key set, ask if the run should be logged anonymously. Only launch this prompt in # environments with a tty. if not self.api.api_key and sys.stdin.isatty(): # Require anonymous mode to be explicitly enabled for now if os.environ.get(env.ANONYMOUS) != "enable": return False termlog( 'No API key found. Would you like to log runs anonymously to {}? (y/n)' .format(self.api.app_url)) resp = str(input().lower().strip()) while not (resp == 'y' or resp == 'n'): termlog('Invalid response. Please enter y/n.') resp = str(input()).lower().strip() if resp == 'y': key = self.api.create_anonymous_api_key() url = self.api.app_url + '/login?apiKey={}'.format(key) termlog( 'Your anonymous login link: {}. Do not share or lose this link!' .format(url)) os.environ[env.API_KEY] = key self.api.set_setting('anonymous', True) util.write_netrc(self.api.api_url, "user", key) util.write_settings(settings=self.api.settings()) self.api.reauth() return True return False
def _init_jupyter(run, job_type): """Asks for user input to configure the machine if it isn't already and creates a new run. Log pushing and system stats don't start until `wandb.monitor()` is called. """ global http_api # TODO: Should we log to jupyter? try_to_set_up_logging() if not http_api.api_key: termerror( "Not authenticated. Copy a key from https://app.wandb.ai/profile?message=true" ) key = getpass.getpass("API Key: ").strip() if len(key) == 40: os.environ["WANDB_API_KEY"] = key util.write_netrc(http_api.api_url, "user", key) else: raise ValueError("API Key must be 40 characters long") # Ensure our api client picks up the new key http_api = Api() if not http_api.settings('project'): termerror("No W&B project configured.") slug = six.moves.input("Enter username/project: ").strip() if "/" not in slug: raise ValueError( "Input must contain a slash between username and project") entity, project = slug.split("/") os.environ["WANDB_ENTITY"] = entity os.environ["WANDB_PROJECT"] = project util.write_settings(entity, project, http_api.settings()['base_url']) # Reset settings so they reload http_api._settings = None os.environ["WANDB_JUPYTER"] = "true" run.resume = "allow" http_api.set_current_run_id(run.id) print("W&B Run: %s" % run.get_url(http_api)) print( "Wrap your training loop with `with wandb.monitor():` to display live results." ) try: run.save(api=http_api, job_type=job_type) except (CommError, ValueError) as e: termerror(str(e)) run.set_environment()
def init(ctx): from wandb import _set_stage_dir, __stage_dir__, wandb_dir if __stage_dir__ is None: _set_stage_dir('wandb') if os.path.isdir(wandb_dir()) and os.path.exists( os.path.join(wandb_dir(), "settings")): click.confirm(click.style( "This directory has been configured previously, should we re-configure it?", bold=True), abort=True) else: click.echo( click.style("Let's setup this directory for W&B!", fg="green", bold=True)) if api.api_key is None: ctx.invoke(login) viewer = api.viewer() # Viewer can be `None` in case your API information became invalid, or # in testing if you switch hosts. if not viewer: click.echo( click.style( "Your login information seems to be invalid: can you log in again please?", fg="red", bold=True)) ctx.invoke(login) # This shouldn't happen. viewer = api.viewer() if not viewer: click.echo( click.style( "We're sorry, there was a problem logging you in. Please send us a note at [email protected] and tell us how this happened.", fg="red", bold=True)) sys.exit(1) # At this point we should be logged in successfully. if len(viewer["teams"]["edges"]) > 1: team_names = [e["node"]["name"] for e in viewer["teams"]["edges"]] question = { 'type': 'list', 'name': 'team_name', 'message': "Which team should we use?", 'choices': team_names + ["Manual Entry"] } result = whaaaaat.prompt([question]) # result can be empty on click if result: entity = result['team_name'] else: entity = "Manual Entry" if entity == "Manual Entry": entity = click.prompt("Enter the name of the team you want to use") else: entity = click.prompt("What username or team should we use?", default=viewer.get('entity', 'models')) # TODO: this error handling sucks and the output isn't pretty try: project = prompt_for_project(ctx, entity) except wandb.cli.ClickWandbException: raise ClickException('Could not find team: %s' % entity) util.write_settings(entity, project, api.settings()) with open(os.path.join(wandb_dir(), '.gitignore'), "w") as file: file.write("*\n!settings") click.echo( click.style("This directory is configured! Next, track a run:\n", fg="green") + textwrap.dedent("""\ * In your training script: {code1} {code2} * then `{run}`. """).format( code1=click.style("import wandb", bold=True), code2=click.style("wandb.init()", bold=True), run=click.style("python <train.py>", bold=True), # saving this here so I can easily put it back when we re-enable # push/pull # """ # * Run `{push}` to manually add a file. # * Pull popular models into your project with: `{pull}`. # """ # push=click.style("wandb push run_id weights.h5", bold=True), # pull=click.style("wandb pull models/inception-v4", bold=True) ))
def login(key, server=LocalServer(), browser=True, anonymous=False): global api key = key[0] if len(key) > 0 else None # Import in here for performance reasons import webbrowser browser = util.launch_browser(browser) # Go through the regular user login flow first, unless --anonymous is specified. if not key and not anonymous: # TODO: use Oauth?: https://community.auth0.com/questions/6501/authenticating-an-installed-cli-with-oidc-and-a-th url = api.app_url + '/authorize' if key or not browser: launched = False else: launched = webbrowser.open_new_tab(url + "?{}".format(server.qs())) if launched: click.echo('Opening [{}] in your default browser'.format(url)) server.start(blocking=False) elif not key: click.echo( "You can find your API keys in your browser here: {}".format( url)) def cancel_prompt(*args): raise KeyboardInterrupt() # Hijacking this signal broke tests in py2... # if not os.getenv("WANDB_TEST"): signal.signal(signal.SIGINT, cancel_prompt) try: key = key or click.prompt("Paste an API key from your profile", value_proc=lambda x: x.strip()) except Abort: if server.result.get("key"): key = server.result["key"][0] # If we still don't have a key, go through the anonymous user flow if we're running interactively. if not key: try: click.confirm( 'No API key found. Would you like to log runs anonymously?', abort=True) anonymous = True except Abort: anonymous = False # Go through the anonymous login flow. if not key and anonymous: if api.api_key: click.confirm( 'You are already logged in. Are you sure you want to create a new anonymous login?', abort=True) # Generate a new anonymous user and use its API key. key = api.create_anonymous_api_key() url = api.app_url + '/login?apiKey={}'.format(key) if browser: webbrowser.open_new_tab(url) click.echo( "Your anonymous login link: {}. Do not share or lose this link!". format(url)) if key: # TODO: get the username here... # username = api.viewer().get('entity', 'models') if util.write_netrc(api.api_url, "user", key): api.set_setting('anonymous', anonymous) util.write_settings(settings=api.settings()) click.secho("Successfully logged in to Weights & Biases!", fg="green") else: click.echo("No key provided, please try again") # reinitialize API to create the new client api = InternalApi() return key
def init(ctx): from wandb import _set_stage_dir, __stage_dir__, wandb_dir if __stage_dir__ is None: _set_stage_dir('wandb') if os.path.isdir(wandb_dir()): click.confirm(click.style( "This directory has been configured previously, should we re-configure it?", bold=True), abort=True) else: click.echo(click.style( "Let's setup this directory for W&B!", fg="green", bold=True)) global IS_INIT if api.api_key is None: ctx.invoke(login) IS_INIT = True viewer = api.viewer() if len(viewer["teams"]["edges"]) > 1: team_names = [e["node"]["name"] for e in viewer["teams"]["edges"]] question = { 'type': 'list', 'name': 'team_name', 'message': "Which team should we use?", 'choices': team_names + ["Manual Entry"] } result = whaaaaat.prompt([question]) # result can be empty on click if result: entity = result['team_name'] else: entity = "Manual Entry" if entity == "Manual Entry": entity = click.prompt("Enter the name of the team you want to use") else: entity = click.prompt("What username or team should we use?", default=viewer.get('entity', 'models')) # TODO: this error handling sucks and the output isn't pretty try: project = prompt_for_project(ctx, entity) except wandb.cli.ClickWandbException: raise ClickException('Could not find team: %s' % entity) util.write_settings(entity, project, api.settings()['base_url']) with open(os.path.join(wandb_dir(), '.gitignore'), "w") as file: file.write("*\n!settings") click.echo(click.style("This directory is configured! Next, track a run:\n", fg="green") + textwrap.dedent("""\ * In your training script: {code1} {code2} * then `{run}`. """).format( code1=click.style("import wandb", bold=True), code2=click.style("wandb.init()", bold=True), run=click.style("python <train.py>", bold=True), # saving this here so I can easily put it back when we re-enable # push/pull #""" #* Run `{push}` to manually add a file. #* Pull popular models into your project with: `{pull}`. #""" # push=click.style("wandb push run_id weights.h5", bold=True), # pull=click.style("wandb pull models/inception-v4", bold=True) ))