Repository: dask/dask
File: dask/cli.py (Python)

Code before:
                click.echo_via_pager(dump(data))
            else:
                click.echo(data)
        except KeyError:
            click.echo(click.style(f"Section not found: {key}", fg="red"), err=True)
            exit(1)


@config.command(name="set")
@click.argument("key", default=None, required=False)
@click.argument("value", default=None, required=False)
def config_set(key=None, value=None):
    """Set a Dask config key to a new value"""
    if key in (None, ""):
        click.echo(
            click.style(
                """Config key not specified. Are you looking for "dask config list"?"""
            ),
            err=True,
        )
        exit(1)
    else:
        try:
            value = ast.literal_eval(value)
        except (ValueError, SyntaxError):  # Not a literal
            pass
        dask.config.set({key: value})
        _, path = save_config(dask.config.config)
        click.echo(f"Updated [{key}] to [{value}], config saved to {path}")


def save_config(new_config: dict) -> tuple[dict, str]:
    """
    Save new config values to dask config file,
    return new config and path to file.
    """
    config_file = os.path.join(dask.config.PATH, "dask.yaml")
    os.makedirs(os.path.dirname(config_file), exist_ok=True)
    configs = dask.config.collect_yaml([config_file])

    config = dask.config.merge(*configs, new_config)
    try:
        with open(config_file, "w") as f:
            f.write(dump(config))
    except OSError as e:
        raise RuntimeError(
            f"""

For some reason we couldn't write config to {config_file}.
Perhaps you don't have permissions here?


Review comment (refactor):
This is different from the same code in dask/config.py and doesn't process null/none correctly:
https://github.com/dask/dask/blob/9a1d4f14e29f279cd1eb3154367cc0806fcebbe4/dask/config.py#L260-L266

Maybe a minor refactor of `dask.config.collect_env` so that you can reuse the same code to parse the value here would be more robust in the long term than trying to keep the functionality aligned in the two places?


Code after:
            else:
                click.echo(data)
        except KeyError:
            click.echo(click.style(f"Section not found: {key}", fg="red"), err=True)
            exit(1)


@config.command(name="set")
@click.argument("key", default=None, required=False)
@click.argument("value", default=None, required=False)
def config_set(key=None, value=None):
    """Set a Dask config key to a new value"""
    if key in (None, ""):
        click.echo(
            click.style(
                """Config key not specified. Are you looking for "dask config list"?"""
            ),
            err=True,
        )
        exit(1)
    else:
        value = dask.config.interpret_value(value)
        _, path = save_config({key: value})
        click.echo(f"Updated [{key}] to [{value}], config saved to {path}")


def save_config(new_config: dict) -> tuple[dict, pathlib.Path]:
    """
    Save new config values to dask config file,
    return new config and path to file.
    """
    config_file = pathlib.Path(dask.config.PATH).joinpath("dask.yaml")
    config_file.parent.mkdir(exist_ok=True, parents=True)
    if config_file.exists():
        with open(str(config_file)) as f:
            config = yaml.safe_load(f) or dict()
    else:
        config = dict()

    dask.config.set(new_config, config=config)

    try:
        config_file.write_text(yaml.dump(config))
    except OSError as e:
        raise RuntimeError(
            f"""

For some reason we couldn't write config to {config_file}.
Perhaps you don't have permissions here?

You can change the directory where Dask writes config files