def migrate_scripts(self):
        if "scripts" not in self._pipenv:
            return

        for name, cmd in self._pipenv["scripts"].items():
            if "scripts" not in self._pyproject["tool"]["poetry"]:
                self._pyproject["tool"]["poetry"]["scripts"] = table()
            self._pyproject["tool"]["poetry"]["scripts"].add(name, cmd)
Beispiel #2
0
 def from_string(cls, string):
     document = tomlkit.loads(string)
     # tomlkit's setdefault is broken, see sdipater/tomlkit#49
     for each in "virtualenv", "bundle":
         if each not in document:
             document[each] = tomlkit.table()
     _check_for_duplicated_links(document["virtualenv"].values())
     return cls(contents=document)
Beispiel #3
0
def _add_config_values_to_toml_object(toml_obj: TOMLContainer, data: typing.Dict[str, typing.Union[dict, ConfigValue]]):
    for key_name, key_data in data.items():
        if isinstance(key_data, dict):
            table = tomlkit.table()
            _add_config_values_to_toml_object(table, key_data)
            toml_obj[key_name] = table
        else:
            key_data.add_to_toml_obj(toml_obj, _NOT_SET)
Beispiel #4
0
def test_uses_pyproject_if_tbump_toml_is_missing(test_data_path: Path,
                                                 tmp_path: Path) -> None:

    expected_file = tbump.config.get_config_file(test_data_path)
    parsed_config = expected_file.get_parsed()
    tools_config = tomlkit.table()
    tools_config.add("tbump", parsed_config)

    pyproject_config = tomlkit.table()
    pyproject_config.add("tool", tools_config)
    to_write = tomlkit.dumps(pyproject_config)

    pyproject_toml = tmp_path / "pyproject.toml"
    pyproject_toml.write_text(to_write)

    actual_file = tbump.config.get_config_file(tmp_path)
    assert actual_file.get_config() == expected_file.get_config()
Beispiel #5
0
    def generate_poetry_content(self,
                                original: PyProjectTOML | None = None) -> str:
        template = POETRY_DEFAULT

        content = loads(template)

        poetry_content = content["tool"]["poetry"]
        poetry_content["name"] = self._project
        poetry_content["version"] = self._version
        poetry_content["description"] = self._description
        poetry_content["authors"].append(self._author)

        if self._license:
            poetry_content["license"] = self._license
        else:
            poetry_content.remove("license")

        poetry_content["readme"] = f"README.{self._readme_format}"
        packages = self.get_package_include()
        if packages:
            poetry_content["packages"].append(packages)
        else:
            poetry_content.remove("packages")

        poetry_content["dependencies"]["python"] = self._python

        for dep_name, dep_constraint in self._dependencies.items():
            poetry_content["dependencies"][dep_name] = dep_constraint

        if self._dev_dependencies:
            for dep_name, dep_constraint in self._dev_dependencies.items():
                poetry_content["group"]["dev"]["dependencies"][
                    dep_name] = dep_constraint
        else:
            del poetry_content["group"]

        # Add build system
        build_system = table()
        build_system_version = ""

        if BUILD_SYSTEM_MIN_VERSION is not None:
            build_system_version = ">=" + BUILD_SYSTEM_MIN_VERSION
        if BUILD_SYSTEM_MAX_VERSION is not None:
            if build_system_version:
                build_system_version += ","
            build_system_version += "<" + BUILD_SYSTEM_MAX_VERSION

        build_system.add("requires", ["poetry-core" + build_system_version])
        build_system.add("build-backend", "poetry.core.masonry.api")

        content.add("build-system", build_system)

        content = dumps(content)

        if original and original.file.exists():
            content = dumps(original.data) + "\n" + content

        return content
Beispiel #6
0
    def _add_entrypoints(section, entrypoints):
        # drop old console_scripts
        if 'scripts' in section:
            scripts = {e.name for e in entrypoints if e.group == 'console_scripts'}
            for script_name in section['scripts']:
                if script_name not in scripts:
                    del section['scripts'][script_name]

        # add console_scripts
        for entrypoint in entrypoints:
            if entrypoint.group != 'console_scripts':
                continue
            if 'scripts' not in section:
                section['scripts'] = tomlkit.table()
            if entrypoint.extras:
                content = tomlkit.inline_table()
                content['callable'] = entrypoint.path
                content['extras'] = entrypoint.extras
            else:
                content = entrypoint.path
            section['scripts'][entrypoint.name] = content

        # drop old plugins
        if 'plugins' in section:
            groups = defaultdict(set)
            for entrypoint in entrypoints:
                if entrypoint.group != 'console_scripts':
                    groups[entrypoint.group].add(entrypoint.name)
            for group_name, group_content in dict(section['plugins']):
                if group_name not in groups:
                    del section['plugins'][group_name]
                    continue
                for script_name in group_content:
                    if script_name not in groups[group_name]:
                        del section['plugins'][group_name][script_name]

        # add plugins
        for entrypoint in entrypoints:
            if entrypoint.group == 'console_scripts':
                continue
            if 'plugins' not in section:
                section['plugins'] = tomlkit.table()
            if entrypoint.group not in section['plugins']:
                section['plugins'][entrypoint.group] = tomlkit.table()
            section['plugins'][entrypoint.group][entrypoint.name] = entrypoint.path
Beispiel #7
0
def do_import(
    project: Project,
    filename: str,
    format: Optional[str] = None,
    options: Optional[Namespace] = None,
) -> None:
    """Import project metadata from given file.

    :param project: the project instance
    :param filename: the file name
    :param format: the file format, or guess if not given.
    :param options: other options parsed to the CLI.
    """
    if not format:
        for key in FORMATS:
            if FORMATS[key].check_fingerprint(project, filename):
                break
        else:
            raise PdmUsageError("Can't derive the file format automatically, "
                                "please specify it via '-f/--format' option.")
    else:
        key = format
    if options is None:
        options = Namespace(dev=False, section=None)
    project_data, settings = FORMATS[key].convert(project, filename, options)
    pyproject = project.pyproject or tomlkit.document()

    if "tool" not in pyproject or "pdm" not in pyproject["tool"]:
        setdefault(pyproject, "tool", {})["pdm"] = tomlkit.table()

    pyproject["tool"]["pdm"].update(settings)

    if "project" not in pyproject:
        pyproject.add("project", tomlkit.table())
        pyproject["project"].add(tomlkit.comment("PEP 621 project metadata"))
        pyproject["project"].add(
            tomlkit.comment("See https://www.python.org/dev/peps/pep-0621/"))

    pyproject["project"].update(project_data)
    pyproject["build-system"] = {
        "requires": ["pdm-pep517"],
        "build-backend": "pdm.pep517.api",
    }
    project.pyproject = pyproject
    project.write_pyproject()
Beispiel #8
0
    def dump(self, configs, path):
        doc = tomlkit.document()
        root_comment = getattr(configs, '__doc__', '')

        def add_comment(sec, comment):
            for line in textwrap.wrap(comment.strip()):
                sec.add(tomlkit.comment(line))

        def add_value(sec, k, v):
            is_none = v is None
            if is_none:
                sec.add(tomlkit.comment(f'{k} = # Uncomment to use'))
            else:
                sec.add(k, v)
            return not is_none

        if root_comment:
            add_comment(doc, root_comment.strip())
            doc.add(tomlkit.nl())

        for p, value, prop in configs.get_prop_paths():
            section = doc
            key = p
            if '.' in p:
                parts = p.split('.')
                key = parts[-1]

                for part in parts[:-1]:
                    section = section[part]

            if isinstance(value, Nestable):
                # Just add a table for those.
                table = tomlkit.table()
                section.add(key, table)
                if prop.comment is not None:
                    add_comment(table, prop.comment)
                    table.add(tomlkit.nl())
            else:
                if prop.comment is not None:
                    if len(prop.comment) > 40:
                        # Only short comments are inlined.
                        section.add(tomlkit.nl())
                        add_comment(section, prop.comment)
                        add_value(section, key, value)
                    else:
                        good = add_value(section, key, value)
                        if good:
                            if isinstance(value, bool):
                                item = section.item(key)
                            else:
                                item = section[key]
                            item.comment(prop.comment)
                else:
                    add_value(section, key, value)

        with open(path, 'w') as file:
            file.write(tomlkit.dumps(doc))
Beispiel #9
0
def source_to_table(source: Source) -> Table:
    from tomlkit import nl
    from tomlkit import table

    source_table: Table = table()
    for key, value in source.to_dict().items():
        source_table.add(key, value)
    source_table.add(nl())
    return source_table
Beispiel #10
0
 def _get_pipfile_section(self, develop, insert=True):
     name = "dev-packages" if develop else "packages"
     try:
         section = self.pipfile[name]
     except KeyError:
         section = plette.models.PackageCollection(tomlkit.table())
         if insert:
             self.pipfile[name] = section
     return section
    def test_basic(self):
        t = table()
        t.append('name', 'mypackage')
        t.append('version', '1.2.3')

        packageName, packageVersion = self.__lock2PyprojectConverter.convert(t)

        self.assertEqual('mypackage', packageName)
        self.assertEqual('1.2.3', packageVersion)
Beispiel #12
0
    def create(self, name: str = None):
        if self.config_path:
            logger.error("Config file already initialized: {config}",
                         config=self.config_path)
            return
        _name = name or os.path.basename(os.getcwd())
        config_root = os.path.join(os.getcwd(), name or "")
        self.config_path = os.path.join(config_root, "pyproject.toml")
        if os.path.exists(self.config_path):
            logger.error("Config file already exists at: {config}",
                         config=self.config_path)
            return
        logger.info("Creating project: {path}", path=config_root)

        if not os.path.exists(config_root):
            os.mkdir(config_root)

        project_conf = document()

        poetry_meta = table()
        poetry_meta.add("name", _name)
        poetry_meta.add("version", "0.0.1")
        poetry_meta.add("description", "Just an opinionated photo stream site")
        project_conf.add("tool.poetry", poetry_meta)

        poetry_deps = table()
        poetry_deps.add("python", "^3.8")
        poetry_deps.add(__title__, "*")
        project_conf.add("tool.poetry.dependencies", poetry_deps)

        build_sys = table()
        build_sys.add("requires", ["poetry-core>=1.0.0"])
        build_sys.add("build-backend", "poetry.masonry.api")
        project_conf.add("build-system", build_sys)

        meta = table()
        meta.add("name", _name)
        meta.add("author", "John Smith")
        meta.add("author_bio", "Just a photographer")
        project_conf.add("tool.humber.meta", meta)

        with open(self.config_path, "w", encoding="utf-8") as f:
            f.write(project_conf.as_string())
        logger.info("Created new config: {conf}", conf=self.config_path)
Beispiel #13
0
def create_config_file(config: Config) -> None:
    doc = tomlkit.document()
    doc.add("theme", config.theme)
    sitemeta = tomlkit.table()
    sitemeta.add("title", config.sitemeta.title)
    sitemeta.add("author", config.sitemeta.author)
    sitemeta.add("language_code", config.sitemeta.language_code)
    sitemeta.add("year_of_publication", config.sitemeta.year_of_publication)
    doc.add("sitemeta", sitemeta)
    write_file("config.toml", doc.as_string())
Beispiel #14
0
    def update_pyproject_version(self, new_version: str,) -> None:
        """
        Update the version in the pyproject.toml file
        """
        version = safe_version(new_version)

        pyproject_toml = tomlkit.parse(self.pyproject_toml_path.read_text())

        if 'tool' not in pyproject_toml:
            tool_table = tomlkit.table()
            pyproject_toml['tool'] = tool_table

        if 'poetry' not in pyproject_toml['tool']:
            poetry_table = tomlkit.table()
            pyproject_toml['tool'].add('poetry', poetry_table)

        pyproject_toml['tool']['poetry']['version'] = version

        self.pyproject_toml_path.write_text(tomlkit.dumps(pyproject_toml))
Beispiel #15
0
def reorder_source_keys(data):
    # type: ignore
    sources = data["source"]  # type: sources_type
    for i, entry in enumerate(sources):
        table = tomlkit.table()  # type: Mapping
        table["name"] = entry["name"]
        table["url"] = entry["url"]
        table["verify_ssl"] = entry["verify_ssl"]
        data["source"][i] = table
    return data
Beispiel #16
0
    def dumps(self, reqs, project: RootDependency, content=None) -> str:
        doc = tomlkit.parse(content) if content else tomlkit.document()
        doc['package'] = [self._format_req(req=req) for req in reqs]

        # add extras
        extras = defaultdict(list)
        for req in reqs:
            if req.is_main:
                for extra in req.main_envs:
                    extras[extra].append(req.name)
            if req.is_dev:
                for extra in req.dev_envs:
                    extras[extra].append(req.name)
        if extras:
            doc['extras'] = dict(extras)

        # add repositories
        sources = tomlkit.aot()
        if not project.dependencies:
            project.attach_dependencies([req.dep for req in reqs])
        for repo in project.warehouses:
            if isinstance(repo, WarehouseLocalRepo):
                continue
            source = tomlkit.table()
            source['name'] = repo.name
            source['url'] = repo.pretty_url
            sources.append(source)
        if sources:
            doc['source'] = sources

        doc['metadata'] = {
            # sha256 of tool.poetry section from pyproject.toml
            # 'content-hash': ...,
            # 'platform': '*',
            'python-versions': str(project.python),
        }

        doc['metadata']['hashes'] = tomlkit.table()
        for req in reqs:
            doc['metadata']['hashes'][req.name] = list(req.hashes or [])

        return tomlkit.dumps(doc)
Beispiel #17
0
def dict_to_toml(d):
    import tomlkit

    toml = tomlkit.document()
    toml.add(tomlkit.comment("Autogenertod by anysnake"))
    for key, sub_d in d.items():
        table = tomlkit.table()
        for k, v in sub_d.items():
            table.add(k, v)
        toml.add(key, table)
    return toml
Beispiel #18
0
def defaults(commented):
    table = tomlkit.table()
    table['model_kwargs'] = collect_kwarg_defaults(PauliNet.from_hf,
                                                   DEEPQMC_MAPPING)
    table['train_kwargs'] = collect_kwarg_defaults(train, DEEPQMC_MAPPING)
    table['evaluate_kwargs'] = collect_kwarg_defaults(evaluate,
                                                      DEEPQMC_MAPPING)
    lines = tomlkit.dumps(table).split('\n')
    if commented:
        lines = ['# ' + l if ' = ' in l and l[0] != '#' else l for l in lines]
    click.echo('\n'.join(lines), nl=False)
Beispiel #19
0
def reorder_source_keys(data):
    # type: ignore
    sources = data["source"]  # type: sources_type
    for i, entry in enumerate(sources):
        table = tomlkit.table()  # type: Mapping
        source_entry = PipfileLoader.populate_source(entry.copy())
        table["name"] = source_entry["name"]
        table["url"] = source_entry["url"]
        table["verify_ssl"] = source_entry["verify_ssl"]
        data["source"][i] = table
    return data
    def test_git(self):
        t = table()
        t.append('name', 'mypackage')
        t.append('version', '1.2.3')

        tr = table()
        tr.append('reference', '0e2068c02f72b9d3092ff8343aab72cd606fc983')
        tr.append('type', 'git')
        tr.append('url', 'https://github.com/bricksflow/dbx-deploy.git')

        t.append('source', tr)

        packageName, packageDefinition = self.__lock2PyprojectConverter.convert(
            t)

        it = inline_table()
        it.append('git', 'https://github.com/bricksflow/dbx-deploy.git')
        it.append('rev', '0e2068c02f72b9d3092ff8343aab72cd606fc983')

        self.assertEqual('mypackage', packageName)
        self.assertEqual(it, packageDefinition)
Beispiel #21
0
    def _make_env(from_format, from_path, to_format, to_path):
        table = tomlkit.table()

        table['from'] = tomlkit.inline_table()
        table['from']['format'] = from_format
        table['from']['path'] = from_path

        table['to'] = tomlkit.inline_table()
        table['to']['format'] = to_format
        table['to']['path'] = to_path

        return table
Beispiel #22
0
    def _make_env(from_format: str, from_path: str, to_format: str, to_path: str) -> Table:
        table = tomlkit.table()

        table['from'] = tomlkit.inline_table()
        table['from']['format'] = from_format
        table['from']['path'] = from_path

        table['to'] = tomlkit.inline_table()
        table['to']['format'] = to_format
        table['to']['path'] = to_path

        return table
Beispiel #23
0
    def generate_poetry_content(self) -> TOMLDocument:
        template = POETRY_DEFAULT

        content: dict[str, Any] = loads(template)

        poetry_content = content["tool"]["poetry"]
        poetry_content["name"] = self._project
        poetry_content["version"] = self._version
        poetry_content["description"] = self._description
        poetry_content["authors"].append(self._author)

        if self._license:
            poetry_content["license"] = self._license
        else:
            poetry_content.remove("license")

        poetry_content["readme"] = f"README.{self._readme_format}"
        packages = self.get_package_include()
        if packages:
            poetry_content["packages"].append(packages)
        else:
            poetry_content.remove("packages")

        poetry_content["dependencies"]["python"] = self._python

        for dep_name, dep_constraint in self._dependencies.items():
            poetry_content["dependencies"][dep_name] = dep_constraint

        if self._dev_dependencies:
            for dep_name, dep_constraint in self._dev_dependencies.items():
                poetry_content["group"]["dev"]["dependencies"][
                    dep_name] = dep_constraint
        else:
            del poetry_content["group"]

        # Add build system
        build_system = table()
        build_system_version = ""

        if BUILD_SYSTEM_MIN_VERSION is not None:
            build_system_version = ">=" + BUILD_SYSTEM_MIN_VERSION
        if BUILD_SYSTEM_MAX_VERSION is not None:
            if build_system_version:
                build_system_version += ","
            build_system_version += "<" + BUILD_SYSTEM_MAX_VERSION

        build_system.add("requires", ["poetry-core" + build_system_version])
        build_system.add("build-backend", "poetry.core.masonry.api")

        assert isinstance(content, TOMLDocument)
        content.add("build-system", build_system)

        return content
Beispiel #24
0
    def _format_req(self, req):
        result = tomlkit.table()
        for name, value in req:
            if name in self.fields:
                if isinstance(value, tuple):
                    value = list(value)
                result[name] = value
        result['category'] = 'dev' if req.is_dev else 'main'
        if 'version' not in result:
            result['version'] = '*'
        result['version'] = result['version'].lstrip('=')
        if req.markers:
            result['marker'] = req.markers

        # add link
        if req.link and (req.git or isinstance(req.link, DirLink)):
            result['source'] = tomlkit.table()
            if req.git:
                result['source']['type'] = 'git'
            elif isinstance(req.link, DirLink):
                result['source']['type'] = 'directory'
            result['source']['url'] = req.link.short
            if req.rev:
                result['source']['reference'] = req.rev
        elif isinstance(req.dep.repo, WarehouseBaseRepo):
            repo = req.dep.repo.repos[0]
            result['source'] = tomlkit.table()
            result['source']['type'] = 'legacy'
            result['source']['url'] = repo.pretty_url
            result['source']['reference'] = repo.name

        # add dependencies
        deps = req.dep.dependencies
        if deps:
            result['dependencies'] = tomlkit.table()
            for dep in deps:
                result['dependencies'][dep.raw_name] = str(
                    dep.constraint) or '*'

        return result
Beispiel #25
0
def create_test(test):
    '''Create conversion test table.'''

    conversion_test = tomlkit.table()
    float64 = Float64(test)
    mantissa = float64.mantissa()
    exponent = float64.exponent()
    conversion_test.add('UID', '')
    conversion_test.add('str', test)
    conversion_test.add('hex', float64.to_hex())
    conversion_test.add('int', '{}*2^{}'.format(mantissa, exponent))

    return conversion_test
Beispiel #26
0
    def add_property(self, key, value):  # type: (str, Any) -> None
        with self.secure() as config:
            keys = key.split(".")

            for i, key in enumerate(keys):
                if key not in config and i < len(keys) - 1:
                    config[key] = table()

                if i == len(keys) - 1:
                    config[key] = value
                    break

                config = config[key]
def generate(template: settings_template, *, table: bool = False) -> document_or_table:
    """Generates a TOML document or table from a provided settings template"""
    document = tomlkit.table() if table else tomlkit.TOMLDocument()
    for item in template:
        match item:
            case Option():
                document.add(item.key, item.value)
            case tomlkit.api.Comment() | tomlkit.api.Whitespace():
                document.add(item)
            case _:
                raise TypeError('Template can only contain Option, Comment and Whitespace items')

    return document
Beispiel #28
0
def migrate_pyproject(project: Project):
    """Migrate the legacy pyproject format to PEP 621"""

    if project.pyproject and "project" in project.pyproject:
        pyproject = project.pyproject
        settings = {}
        updated_fields = []
        for field in ("includes", "excludes", "build", "package-dir"):
            if field in pyproject["project"]:
                updated_fields.append(field)
                settings[field] = pyproject["project"][field]
                del pyproject["project"][field]
        if "dev-dependencies" in pyproject["project"]:
            if pyproject["project"]["dev-dependencies"]:
                settings["dev-dependencies"] = {
                    "dev": pyproject["project"]["dev-dependencies"]
                }
            del pyproject["project"]["dev-dependencies"]
            updated_fields.append("dev-dependencies")
        if updated_fields:
            if "tool" not in pyproject or "pdm" not in pyproject["tool"]:
                setdefault(pyproject, "tool", {})["pdm"] = tomlkit.table()
            pyproject["tool"]["pdm"].update(settings)
            project.pyproject = pyproject
            project.write_pyproject()
            project.core.ui.echo(
                f"{termui.yellow('[AUTO-MIGRATION]')} These fields are moved from "
                f"[project] to [tool.pdm] table: {updated_fields}",
                err=True,
            )
        return

    if not project.pyproject_file.exists() or not FORMATS["legacy"].check_fingerprint(
        project, project.pyproject_file
    ):
        return

    project.core.ui.echo(
        f"{termui.yellow('[AUTO-MIGRATION]')} Legacy pdm 0.x metadata detected, "
        "migrating to PEP 621...",
        err=True,
    )
    do_import(project, project.pyproject_file, "legacy")
    project.core.ui.echo(
        termui.green("pyproject.toml")
        + termui.yellow(
            " has been migrated to PEP 621 successfully. "
            "Now you can safely delete the legacy metadata under [tool.pdm] table."
        ),
        err=True,
    )
Beispiel #29
0
def do_init(
    project: Project,
    name: str = "",
    version: str = "",
    license: str = "MIT",
    author: str = "",
    email: str = "",
    python_requires: str = "",
) -> None:
    """Bootstrap the project and create a pyproject.toml"""
    data = {
        "tool": {
            "pdm": {
                "name": name,
                "version": version,
                "description": "",
                "author": f"{author} <{email}>",
                "license": license,
                "homepage": "",
                "dependencies": tomlkit.table(),
                "dev-dependencies": tomlkit.table(),
            }
        },
        "build-system": {
            "requires": ["pdm"],
            "build-backend": "pdm.builders.api"
        },
    }
    if python_requires and python_requires != "*":
        get_specifier(python_requires)
        data["tool"]["pdm"]["python_requires"] = python_requires
    if not project.pyproject:
        project._pyproject = data
    else:
        project._pyproject.setdefault("tool", {})["pdm"] = data["tool"]["pdm"]
        project._pyproject["build-system"] = data["build-system"]
    project.write_pyproject()
    project.environment.write_site_py()
Beispiel #30
0
def format_lockfile(mapping, fetched_dependencies, summary_collection):
    """Format lock file from a dict of resolved candidates, a mapping of dependencies
    and a collection of package summaries.
    """
    packages = tomlkit.aot()
    file_hashes = tomlkit.table()
    for k, v in sorted(mapping.items()):
        base = tomlkit.table()
        base.update(v.as_lockfile_entry())
        base.add("summary", summary_collection[strip_extras(k)[0]])
        deps = tomlkit.table()
        for r in fetched_dependencies[k].values():
            name, req = r.as_req_dict()
            if getattr(req, "items", None) is not None:
                deps.add(name, make_inline_table(req))
            else:
                deps.add(name, req)
        if len(deps) > 0:
            base.add("dependencies", deps)
        packages.append(base)
        if v.hashes:
            key = f"{k} {v.version}"
            array = tomlkit.array()
            array.multiline(True)
            for filename, hash_value in v.hashes.items():
                inline = make_inline_table({
                    "file": filename,
                    "hash": hash_value
                })
                array.append(inline)
            if array:
                file_hashes.add(key, array)
    doc = tomlkit.document()
    doc.add("package", packages)
    metadata = tomlkit.table()
    metadata.add("files", file_hashes)
    doc.add("metadata", metadata)
    return doc
Beispiel #31
0
    def add_property(self, key, value):
        keys = key.split(".")

        config = self._content
        for i, key in enumerate(keys):
            if key not in config and i < len(keys) - 1:
                config[key] = table()

            if i == len(keys) - 1:
                config[key] = value
                break

            config = config[key]

        self.dump()