def mac_gpu_check(job_mode: conf.JobMode, command: str) -> None: """If the command depends on 'docker run' and is running on a Mac, fail fast.""" if conf.gpu(job_mode) and command in ("shell", "notebook", "run"): u.err("\n'caliban {}' doesn't support GPU usage on Macs! Please pass ". format(command) + "--nogpu to use this command.\n\n") u.err( "(GPU mode is fine for 'caliban cloud' from a Mac; just nothing that runs " "locally.)\n\n") sys.exit(1)
def _validate_no_gpu_type(use_gpu: bool, gpu_spec: Optional[ct.GPUSpec]): """Prevents a user from submitting a Cloud job using a CPU image when they've explicitly attempted to set a GPU spec. """ gpu_disabled = not use_gpu if gpu_disabled and gpu_spec is not None: u.err("\n'--nogpu' is incompatible with an explicit --gpu_spec option. " "Please remove one or the other!\n\n") sys.exit(1)
def fatal_errors(): """Context manager meant to wrap an entire program and present schema errors in an easy-to-read way. """ try: yield except FatalSchemaError as e: u.err(f"{e.context}\n{e.message}\n\n") sys.exit(1) except s.SchemaError as e: u.err(f"\n{e.code}\n\n") sys.exit(1)
def validate_script_args(argv: List[str], items: List[str]) -> List[str]: """This validation catches errors where argparse slurps up anything after the required argument as a script_arg, EVEN if it's not separated by a --. We do this instead of just parsing them directly so that we can still have a nice help string provided by argparse. """ # items before the double-dashes, expected script_args after. pre_args, expected = u.split_by(argv, "--") if items == expected: return items # get the extra arguments parsed BEFORE the dash. These were probably meant # to be options to caliban itself. pre_dashes, _ = u.split_by(items, "--") joined = " ".join(pre_dashes) expected_s = " ".join(expected) # caliban arguments before these unexpected arguments. before_pre_dashes = pre_args[:-len(pre_dashes)] pwas = "was" if len(pre_dashes) == 1 else "were" parg = "argument" if len(pre_dashes) == 1 else "arguments" u.err( """\nThe {} '{}' {} supplied after required arguments but before the '--' separator and {} not properly parsed.\n\n""" .format(parg, joined, pwas, pwas)) u.err("if you meant to pass these as script_args, try " "moving them after the --, like this:\n\n") u.err("caliban {} -- {} {}\n\n".format(' '.join(before_pre_dashes), joined, expected_s)) u.err( "Otherwise, if these are in fact caliban keyword arguments, " "please move them before the python script/module name argument.\n\n") sys.exit(1)
def _validate_machine_type(gpu_spec: Optional[ct.GPUSpec], machine_type: Optional[ct.MachineType]): """If both args are provided,makes sure that Cloud supports this particular combination of GPU count, type and machine type. """ if gpu_spec is not None and machine_type is not None: if not gpu_spec.valid_machine_type(machine_type): # Show a list of the allowed types, sorted so that at least the machine # prefixes stick together. allowed = u.enum_vals(gpu_spec.allowed_machine_types()) allowed.sort() u.err(f"\n'{machine_type.value}' isn't a valid machine type " + f"for {gpu_spec.count} {gpu_spec.gpu.name} GPUs.\n\n") u.err(ct.with_advice_suffix("gpu", f"Try one of these: {allowed}")) u.err("\n") sys.exit(1)
def _validate_accelerator_region(spec: Optional[Union[ct.GPUSpec, ct.TPUSpec]], region: ct.Region): """Check that the supplied region is valid for the accelerator specification, if supplied. """ if spec is not None: accel = spec.accelerator_type if not spec.valid_region(region): # Show a list of the allowed types, sorted so that at least the machine # prefixes stick together. allowed = u.enum_vals(spec.allowed_regions()) allowed.sort() u.err("\n'{}' isn't a valid region ".format(region.value) + "for {}s of type {}.\n\n".format(accel, spec.name)) u.err("Try one of these: {}\n\n".format(allowed)) u.err("See this page for more info about regional " + "support for {}s: https://cloud.google.com/ml-engine/docs/regions\n" .format(accel)) sys.exit(1)