def test_getting_inline_table_is_still_an_inline_table():
    content = """\
[tool.poetry]
name = "foo"

[tool.poetry.dependencies]

[tool.poetry.dev-dependencies]
"""

    doc = parse(content)
    poetry_section = doc["tool"]["poetry"]
    dependencies = poetry_section["dependencies"]
    dependencies["foo"] = tomlkit.inline_table()
    dependencies["foo"]["version"] = "^2.0"
    dependencies["foo"]["source"] = "local"
    dependencies["bar"] = tomlkit.inline_table()
    dependencies["bar"]["version"] = "^3.0"
    dependencies["bar"]["source"] = "remote"
    dev_dependencies = poetry_section["dev-dependencies"]
    dev_dependencies["baz"] = tomlkit.inline_table()
    dev_dependencies["baz"]["version"] = "^4.0"
    dev_dependencies["baz"]["source"] = "other"

    assert ("""\
[tool.poetry]
name = "foo"

[tool.poetry.dependencies]
foo = {version = "^2.0", source = "local"}
bar = {version = "^3.0", source = "remote"}

[tool.poetry.dev-dependencies]
baz = {version = "^4.0", source = "other"}
""" == doc.as_string())
Exemple #2
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()
    metadata = 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:
                inline = tomlkit.inline_table()
                inline.update(req)
                deps.add(name, inline)
            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 = tomlkit.inline_table()
                inline.update({"file": filename, "hash": hash_value})
                array.append(inline)
            if array:
                metadata.add(key, array)
    doc = tomlkit.document()
    doc.update({"package": packages, "metadata": metadata})
    return doc
Exemple #3
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
Exemple #4
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
Exemple #5
0
def set_changed_dependencies(changed_dependencies: Dependencies) -> None:
    """update the poerty dependencies in pyproject.toml"""
    pyproject_path = get_pyproject_path()

    # remove the changed dependencies
    pyproject = tomlkit.parse(pyproject_path.read_text())
    dep = pyproject["tool"]["poetry"]["dependencies"]
    for name in changed_dependencies:
        del dep[name]
    pyproject_path.write_text(tomlkit.dumps(pyproject))
    subprocess.call(["poetry", "update"])

    # make the actual change
    pyproject = tomlkit.parse(pyproject_path.read_text())
    dep = pyproject["tool"]["poetry"]["dependencies"]
    for name, req in changed_dependencies.items():
        if isinstance(req, dict):
            if list(req.keys()) == ["version"]:
                req = req["version"]
            else:
                new_req = tomlkit.inline_table()
                new_req.update(req)
                req = new_req

        dep[name] = req
    pyproject_path.write_text(tomlkit.dumps(pyproject))
    subprocess.call(["poetry", "update"])
def test_replace_with_comment():
    content = 'a = "1"'
    doc = parse(content)
    a = tomlkit.item(int(doc["a"]))
    a.comment("`a` should be an int")
    doc["a"] = a
    expected = "a = 1 # `a` should be an int"
    assert doc.as_string() == expected

    content = 'a = "1, 2, 3"'
    doc = parse(content)
    a = tomlkit.array()
    a.comment("`a` should be an array")
    for x in doc["a"].split(","):
        a.append(int(x.strip()))
    doc["a"] = a
    expected = "a = [1, 2, 3] # `a` should be an array"
    assert doc.as_string() == expected

    doc = parse(content)
    a = tomlkit.inline_table()
    a.comment("`a` should be an inline-table")
    for x in doc["a"].split(","):
        i = int(x.strip())
        a.append(chr(ord("a") + i - 1), i)
    doc["a"] = a
    expected = "a = {a = 1, b = 2, c = 3} # `a` should be an inline-table"
    assert doc.as_string() == expected
Exemple #7
0
    def add_dependencies(self,
                         requirements: Dict[str, Requirement],
                         show_message: bool = True) -> None:
        for name, dep in requirements.items():
            if dep.from_section == "default":
                deps = self.tool_settings["dependencies"]
            elif dep.from_section == "dev":
                deps = self.tool_settings["dev-dependencies"]
            else:
                section = f"{dep.from_section}-dependencies"
                if section not in self.tool_settings:
                    self.tool_settings[section] = tomlkit.table()
                deps = self.tool_settings[section]

            matched_name = next(
                filter(lambda k: strip_extras(name)[0] == safe_name(k).lower(),
                       deps.keys()),
                None,
            )
            name_to_save = dep.name if matched_name is None else matched_name
            _, req_dict = dep.as_req_dict()
            if isinstance(req_dict, dict):
                req = tomlkit.inline_table()
                req.update(req_dict)
                req_dict = req
            deps[name_to_save] = req_dict
        self.write_pyproject(show_message)
Exemple #8
0
    def write_toml(self, data, path=None):
        """Writes the given data structure out as TOML."""
        if path is None:
            path = self.pipfile_location
        data = convert_toml_outline_tables(data)
        try:
            formatted_data = tomlkit.dumps(data).rstrip()
        except Exception:
            document = tomlkit.document()
            for section in ("packages", "dev-packages"):
                document[section] = tomlkit.container.Table()
                # Convert things to inline tables — fancy :)
                for package in data.get(section, {}):
                    if hasattr(data[section][package], "keys"):
                        table = tomlkit.inline_table()
                        table.update(data[section][package])
                        document[section][package] = table
                    else:
                        document[section][package] = tomlkit.string(data[section][package])
            formatted_data = tomlkit.dumps(document).rstrip()

        if (
            vistir.compat.Path(path).absolute()
            == vistir.compat.Path(self.pipfile_location).absolute()
        ):
            newlines = self._pipfile_newlines
        else:
            newlines = DEFAULT_NEWLINES
        formatted_data = cleanup_toml(formatted_data)
        with io.open(path, "w", newline=newlines) as f:
            f.write(formatted_data)
        # pipfile is mutated!
        self.clear_pipfile_cache()
Exemple #9
0
    def get_package_include(self) -> InlineTable | None:
        package = inline_table()

        # If a project is created in the root directory (this is reasonable inside a
        # docker container, eg <https://github.com/python-poetry/poetry/issues/5103>)
        # then parts will be empty.
        parts = self._package_path_relative.parts
        if not parts:
            return None

        include = parts[0]
        package.append("include", include)  # type: ignore[no-untyped-call]

        if self.basedir != Path():
            package.append(  # type: ignore[no-untyped-call]
                "from",
                self.basedir.as_posix(),
            )
        else:
            if include == self._project:
                # package include and package name are the same,
                # packages table is redundant here.
                return None

        return package
Exemple #10
0
    def add_package_to_pipfile(self, package, dev=False):
        from .vendor.requirementslib import Requirement

        # Read and append Pipfile.
        p = self.parsed_pipfile
        # Don't re-capitalize file URLs or VCSs.
        if not isinstance(package, Requirement):
            package = Requirement.from_line(package.strip())
        _, converted = package.pipfile_entry
        key = "dev-packages" if dev else "packages"
        # Set empty group if it doesn't exist yet.
        if key not in p:
            p[key] = {}
        name = self.get_package_name_in_pipfile(package.name, dev)
        if name and is_star(converted):
            # Skip for wildcard version
            return
        # Add the package to the group.
        if isinstance(converted, dict):
            package_table = tomlkit.inline_table()
            package_table.update(converted)
            converted = package_table
        p[key][name or package.normalized_name] = converted
        # Write Pipfile.
        self.write_toml(p)
    def __parseLine(self, matches: Match[str]):
        if matches.group(3) is None:
            return [matches.group(1), matches.group(2).strip()]

        it = inline_table()
        it.append('version', matches.group(2))
        it.append('markers', matches.group(3))

        return [matches.group(1), it]
Exemple #12
0
def test_trim_comments_when_building_inline_table():
    table = inline_table()
    row = parse('foo = "bar"  # Comment')
    table.update(row)
    assert table.as_string() == '{foo = "bar"}'
    value = item("foobaz")
    value.comment("Another comment")
    table.append("baz", value)
    assert "# Another comment" not in table.as_string()
Exemple #13
0
def test_items_are_pickable():
    n = item(12)

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "12"

    n = item(12.34)

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "12.34"

    n = item(True)

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "true"

    n = item(datetime(2018, 10, 11, 12, 34, 56, 123456))

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "2018-10-11T12:34:56.123456"

    n = item(date(2018, 10, 11))

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "2018-10-11"

    n = item(time(12, 34, 56, 123456))

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "12:34:56.123456"

    n = item([1, 2, 3])

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == "[1, 2, 3]"

    n = item({"foo": "bar"})

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == 'foo = "bar"\n'

    n = inline_table()
    n["foo"] = "bar"

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == '{foo = "bar"}'

    n = item("foo")

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == '"foo"'

    n = item([{"foo": "bar"}])

    s = pickle.dumps(n)
    assert pickle.loads(s).as_string() == 'foo = "bar"\n'
Exemple #14
0
def format_toml(pdm_settings):
    """Ensure the dependencies are inline tables"""
    for section in pdm_settings:
        if not section.endswith("dependencies"):
            continue
        for name in pdm_settings[section]:
            if getattr(pdm_settings[section][name], "items", None):
                table = tomlkit.inline_table()
                table.update(pdm_settings[section][name])
                pdm_settings[section][name] = table
    def __getStandardDependency(self, dependency: Table):
        it = inline_table()

        if 'marker' in dependency:
            it.append('version', dependency['version'])
            it.append('markers', dependency['marker'])

            return dependency['name'], it

        return dependency['name'], dependency['version']
Exemple #16
0
def test_deleting_inline_table_elemeent_does_not_leave_trailing_separator():
    table = inline_table()
    table["foo"] = "bar"
    table["baz"] = "boom"

    assert '{foo = "bar", baz = "boom"}' == table.as_string()

    del table["baz"]

    assert '{foo = "bar"}' == table.as_string()

    table = inline_table()
    table["foo"] = "bar"

    del table["foo"]

    table["baz"] = "boom"

    assert '{baz = "boom"}' == table.as_string()
Exemple #17
0
def test_inline_table_should_append_a_newline():
    content = "[foo]\nh = 1\n[bar]\nc = 2\n"

    doc = parse(content)
    insert = inline_table()
    insert["z"] = 3
    doc["foo"]["added"] = insert

    result = dumps(doc)

    assert "}[" not in result
Exemple #18
0
 def convert_tomlkit_table(section):
     if isinstance(section, tomlkit.items.Table):
         body = section.value._body
     else:
         body = section._body
     for key, value in body:
         if not key:
             continue
         if hasattr(value, "keys") and not isinstance(
                 value, tomlkit.items.InlineTable):
             table = tomlkit.inline_table()
             table.update(value.value)
             section[key.key] = table
    def migrate_dependencies(self, *, dev: bool = False):
        prefix = "dev-" if dev else ""
        pipenv_key = prefix + "packages"
        poetry_key = prefix + "dependencies"

        for name, ver in self._pipenv[pipenv_key].items():
            if name in self._pyproject["tool"]["poetry"][poetry_key]:
                continue
            if isinstance(ver, dict):
                tmp = inline_table()
                tmp.update(ver)
                ver = tmp
            self._pyproject["tool"]["poetry"][poetry_key].add(name, ver)
Exemple #20
0
def line_to_kv(line):
    match = BREW_LINE_RE.match(line)
    if match is None:
        raise ValueError(f"Don't understand line {line!r}")
    kind, name, arglist = (x.strip() for x in match.groups())
    if arglist:
        args = inline_table()
        for item in arglist.split(','):
            if not item: continue
            k, v = item.split(':')
            args[k.strip()] = v.strip()
        return kind, name, args
    else:
        return kind, name, True
Exemple #21
0
    def _add_entrypoints(section: Table, entrypoints: Tuple[EntryPoint,
                                                            ...]) -> None:
        # drop old console_scripts
        if 'scripts' in section:
            scripts = {
                e.name
                for e in entrypoints if e.group == 'console_scripts'
            }
            for script_name in list(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 section['plugins'].items():
                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
Exemple #22
0
    def get_package_include(self) -> InlineTable | None:
        package = inline_table()

        include = self._package_path_relative.parts[0]
        package.append("include", include)

        if self.basedir != Path():
            package.append("from", self.basedir.as_posix())
        else:
            if include == self._project:
                # package include and package name are the same,
                # packages table is redundant here.
                return None

        return package
Exemple #23
0
 def _reformat_dependency_properties(
     extras: Optional[str], properties: Union[str, Dict[str, Any]]
 ) -> Union[str, InlineTable]:
     formatted = inline_table()
     if extras is not None:
         formatted.update({"extras": extras.split(",")})
     if isinstance(properties, dict):
         formatted.update(translate_properties(properties))
     else:
         formatted.append("version", properties)
     return (
         formatted["version"]
         if len(formatted) == 1 and "version" in formatted.keys()
         else formatted
     )
    def test_basic_withMarkers(self):
        t = table()
        t.append('name', 'mypackage')
        t.append('version', '1.2.3')
        t.append('marker', 'sys_platform == "darwin"')

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

        it = inline_table()
        it.append('version', '1.2.3')
        it.append('markers', 'sys_platform == "darwin"')

        self.assertEqual('mypackage', packageName)
        self.assertEqual(it, packageDefinition)
Exemple #25
0
 def add_line_to_pipfile(self, line, develop):
     from requirementslib import Requirement
     requirement = Requirement.from_line(line)
     section = self._get_pipfile_section(develop=develop)
     key = requirement.normalized_name
     entry = next(iter(requirement.as_pipfile().values()))
     if isinstance(entry, dict):
         # HACK: TOMLKit prefers to expand tables by default, but we
         # always want inline tables here. Also tomlkit.inline_table
         # does not have `update()`.
         table = tomlkit.inline_table()
         for k, v in entry.items():
             table[k] = v
         entry = table
     section[key] = entry
Exemple #26
0
    def _format_requirements(
        self, requirements: List[Dict[str, str]]
    ) -> Dict[str, Union[str, Dict[str, str]]]:
        requires = {}
        for requirement in requirements:
            name = requirement.pop("name")
            if "version" in requirement and len(requirement) == 1:
                constraint = requirement["version"]
            else:
                constraint = inline_table()
                constraint.trivia.trail = "\n"
                constraint.update(requirement)

            requires[name] = constraint

        return requires
Exemple #27
0
    def _format_requirements(
            self, requirements: list[dict[str, str]]) -> Requirements:
        requires: Requirements = {}
        for requirement in requirements:
            name = requirement.pop("name")
            constraint: str | InlineTable
            if "version" in requirement and len(requirement) == 1:
                constraint = requirement["version"]
            else:
                constraint = inline_table()
                constraint.trivia.trail = "\n"
                constraint.update(requirement)

            requires[name] = constraint

        return requires
Exemple #28
0
    def _format_req(self, req: Requirement) -> Union[InlineTable, String]:
        result = tomlkit.inline_table()
        for name, value in req:
            if name in self.fields:
                if isinstance(value, tuple):
                    value = list(value)
                result[name] = value
        if req.prereleases:
            result['allows-prereleases'] = True
        if 'version' not in result and 'git' not in result:
            result['version'] = '*'
        # if we have only version, return string instead of table
        if tuple(result.value) == ('version', ):
            return result['version']

        return result
Exemple #29
0
    def _format_req(self, req):
        result = tomlkit.inline_table()
        for name, value in req:
            if name in self.fields:
                if isinstance(value, tuple):
                    value = list(value)
                result[name] = value
        if 'version' not in result:
            result['version'] = '*'
        # if we have only version, return string instead of table
        if tuple(result.value) == ('version', ):
            return result['version']
        # do not specify version explicit
        if result['version'] == '*':
            del result['version']

        return result
def test_string_output_order_is_preserved_for_out_of_order_tables():
    content = """
[tool.poetry]
name = "foo"

[tool.poetry.dependencies]
python = "^3.6"
bar = "^1.0"


[build-system]
requires = ["poetry-core"]
backend = "poetry.core.masonry.api"


[tool.other]
a = "b"
"""

    doc = parse(content)
    constraint = tomlkit.inline_table()
    constraint["version"] = "^1.0"
    doc["tool"]["poetry"]["dependencies"]["bar"] = constraint

    assert "^1.0" == doc["tool"]["poetry"]["dependencies"]["bar"]["version"]

    expected = """
[tool.poetry]
name = "foo"

[tool.poetry.dependencies]
python = "^3.6"
bar = {version = "^1.0"}


[build-system]
requires = ["poetry-core"]
backend = "poetry.core.masonry.api"


[tool.other]
a = "b"
"""

    assert expected == doc.as_string()
Exemple #31
0
    def handle(self):
        from poetry.installation import Installer
        from poetry.semver import parse_constraint
        from tomlkit import inline_table

        packages = self.argument("name")
        is_dev = self.option("dev")

        if (self.option("git") or self.option("path") or self.option("extras")) and len(
            packages
        ) > 1:
            raise ValueError(
                "You can only specify one package "
                "when using the --git or --path options"
            )

        if self.option("git") and self.option("path"):
            raise RuntimeError("--git and --path cannot be used at the same time")

        section = "dependencies"
        if is_dev:
            section = "dev-dependencies"

        original_content = self.poetry.file.read()
        content = self.poetry.file.read()
        poetry_content = content["tool"]["poetry"]

        if section not in poetry_content:
            poetry_content[section] = {}

        for name in packages:
            for key in poetry_content[section]:
                if key.lower() == name.lower():
                    raise ValueError("Package {} is already present".format(name))

        if self.option("git") or self.option("path"):
            requirements = {packages[0]: ""}
        else:
            requirements = self._determine_requirements(
                packages, allow_prereleases=self.option("allow-prereleases")
            )
            requirements = self._format_requirements(requirements)

            # validate requirements format
            for constraint in requirements.values():
                parse_constraint(constraint)

        for name, _constraint in requirements.items():
            constraint = inline_table()
            constraint["version"] = _constraint

            if self.option("git"):
                del constraint["version"]

                constraint["git"] = self.option("git")
            elif self.option("path"):
                del constraint["version"]

                constraint["path"] = self.option("path")

            if self.option("optional"):
                constraint["optional"] = True

            if self.option("allow-prereleases"):
                constraint["allows-prereleases"] = True

            if self.option("extras"):
                extras = []
                for extra in self.option("extras"):
                    if " " in extra:
                        extras += [e.strip() for e in extra.split(" ")]
                    else:
                        extras.append(extra)

                constraint["extras"] = self.option("extras")

            if self.option("python"):
                constraint["python"] = self.option("python")

            if self.option("platform"):
                constraint["platform"] = self.option("platform")

            if len(constraint) == 1 and "version" in constraint:
                constraint = constraint["version"]

            poetry_content[section][name] = constraint

        # Write new content
        self.poetry.file.write(content)

        # Cosmetic new line
        self.line("")

        # Update packages
        self.reset_poetry()

        installer = Installer(
            self.output,
            self.venv,
            self.poetry.package,
            self.poetry.locker,
            self.poetry.pool,
        )

        installer.dry_run(self.option("dry-run"))
        installer.update(True)
        installer.whitelist(requirements)

        try:
            status = installer.run()
        except Exception:
            self.poetry.file.write(original_content)

            raise

        if status != 0 or self.option("dry-run"):
            # Revert changes
            if not self.option("dry-run"):
                self.error(
                    "\n"
                    "Addition failed, reverting pyproject.toml "
                    "to its original content."
                )

            self.poetry.file.write(original_content)

        return status