diff --git a/pipenv/project.py b/pipenv/project.py index 26b4cf0c..4b90f493 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -8,7 +8,6 @@ import glob import base64 import fnmatch import hashlib -import contoml from first import first from cached_property import cached_property import operator @@ -578,60 +577,31 @@ class Project(object): _pipfile_cache.clear() @staticmethod - def dump_dict(dictionary, write_to, inline=False): - """ - Perform a nested recursive translation of a dictionary structure to a toml object. - - :param dictionary: A base dictionary to translate - :param write_to: The root node which will be mutated by the operation - :param inline: Whether to create inline tables for dictionaries, defaults to False - :return: A new toml hierarchical document - """ - - - def gen_table(inline=False): - if inline: - return tomlkit.inline_table() - return tomlkit.table() - - for key, value in dictionary.items(): - if isinstance(value, dict): - table = gen_table(inline=inline) - for sub_key, sub_value in value.items(): - if isinstance(sub_value, dict): - table[sub_key] = Project.dump_dict( - sub_value, gen_table(inline), inline=inline - ) - else: - table[sub_key] = sub_value - write_to[key] = table - else: - write_to[key] = Project.dump_dict(value, gen_table(inline), inline=inline) + def convert_outline_table(parsed): + """Converts all outline to inline tables""" + if hasattr(parsed, "_body"): # Duck-type that implies tomlkit.api.Container. + empty_inline_table = tomlkit.inline_table else: - write_to[key] = value - return write_to + empty_inline_table = toml.TomlDecoder().get_empty_inline_table + for section in ("packages", "dev-packages"): + table_data = parsed.get(section, {}) + for package, value in table_data.items(): + if hasattr(value, "keys"): + table = empty_inline_table() + table.update(value) + table_data[package] = table + return parsed def _parse_pipfile(self, contents): - # If any outline tables are present... try: data = tomlkit.parse(contents) - # Convert all outline tables to inline tables. - for section in ("packages", "dev-packages"): - table_data = data.get(section, tomlkit.table()) - for package, value in table_data.items(): - if isinstance(value, dict): - table = tomlkit.inline_table() - table.update(value) - table_data[package] = table - else: - table_data[package] = value - data[section] = table_data - return data except Exception: # We lose comments here, but it's for the best.) # Fallback to toml parser, for large files. - toml_decoder = toml.decoder.TomlDecoder() - return toml.loads(contents, decoder=toml_decoder) + data = toml.loads(contents) + if "[packages." in contents or "[dev-packages." in contents: + data = self.convert_outline_table(data) + return data def _read_pyproject(self): pyproject = self.path_to("pyproject.toml") @@ -886,7 +856,11 @@ class Project(object): if path is None: path = self.pipfile_location try: - formatted_data = tomlkit.dumps(data).rstrip() + if hasattr(data, "_body"): + formatted_data = tomlkit.dumps(data).rstrip() + else: + encoder = toml.encoder.TomlPreserveInlineDictEncoder() + formatted_data = toml.dumps(data, encoder=encoder) except Exception: document = tomlkit.document() for section in ("packages", "dev-packages"): diff --git a/tests/integration/test_project.py b/tests/integration/test_project.py index 5deccc84..1e00bbb7 100644 --- a/tests/integration/test_project.py +++ b/tests/integration/test_project.py @@ -143,3 +143,21 @@ six = {{version = "*", index = "pypi"}} f.write(contents) c = p.pipenv('install') assert c.return_code == 0 + + +@pytest.mark.install +@pytest.mark.project +def test_rewrite_outline_table(PipenvInstance, pypi): + with PipenvInstance(pypi=pypi, chdir=True) as p: + with open(p.pipfile_path, 'w') as f: + contents = """ +[packages.requests] +version = "*" + """.strip() + f.write(contents) + c = p.pipenv('install click') + assert c.return_code == 0 + with open(p.pipfile_path) as f: + contents = f.read() + assert "[packages.requests]" not in contents + assert 'requests = { version = "*" }' in contents diff --git a/tests/unit/test_vendor.py b/tests/unit/test_vendor.py index 1894b6ff..704b37fb 100644 --- a/tests/unit/test_vendor.py +++ b/tests/unit/test_vendor.py @@ -106,9 +106,3 @@ class TestPipfileParser: def test_token_date(dt, content): token = create_primitive_token(dt) assert token == tokens.Token(tokens.TYPE_DATE, content) - - -def test_dump_nonascii_string(): - content = 'name = "Stažené"\n' - toml_content = contoml.dumps(contoml.loads(content)) - assert toml_content == content