Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to skip normalising requirement versions #150

Merged
merged 7 commits into from
Nov 1, 2023
13 changes: 12 additions & 1 deletion src/pyproject_fmt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@ class PyProjectFmtNamespace(Namespace):
stdout: bool
indent: int
check: bool
preserve_dependency_versions: bool

@property
def configs(self) -> list[Config]:
""":return: configurations"""
return [Config(toml, toml.read_text(encoding="utf-8"), self.indent) for toml in self.inputs]
return [
Config(
pyproject_toml=toml,
toml=toml.read_text(encoding="utf-8"),
indent=self.indent,
preserve_dependency_versions=self.preserve_dependency_versions,
)
for toml in self.inputs
]


def pyproject_toml_path_creator(argument: str) -> Path:
Expand Down Expand Up @@ -71,6 +80,8 @@ def _build_cli() -> ArgumentParser:
group.add_argument("-s", "--stdout", action="store_true", help=msg)
msg = "check and fail if any input would be formatted, printing any diffs"
group.add_argument("--check", action="store_true", help=msg)
msg = "preserve dependency versions. For example do not change version 1.0.0 to 1"
group.add_argument("--preserve-dependency-versions", action="store_true", help=msg)
gaborbernat marked this conversation as resolved.
Show resolved Hide resolved
parser.add_argument(
"--indent",
type=int,
Expand Down
6 changes: 5 additions & 1 deletion src/pyproject_fmt/formatter/build_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ def fmt_build_system(parsed: TOMLDocument, conf: Config) -> None:
"""
system = cast(Optional[Table], parsed.get("build-system"))
if system is not None:
normalize_pep508_array(cast(Optional[Array], system.get("requires")), conf.indent)
normalize_pep508_array(
requires_array=cast(Optional[Array], system.get("requires")),
indent=conf.indent,
preserve_dependency_versions=conf.preserve_dependency_versions,
)
sorted_array(cast(Optional[Array], system.get("backend-path")), indent=conf.indent)
order_keys(system, ("build-backend", "requires", "backend-path"))
ensure_newline_at_end(system)
Expand Down
1 change: 1 addition & 0 deletions src/pyproject_fmt/formatter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Config:
pyproject_toml: Path
toml: str #: the text to format
indent: int = DEFAULT_INDENT #: indentation to apply
preserve_dependency_versions: bool = False


__all__ = [
Expand Down
11 changes: 9 additions & 2 deletions src/pyproject_fmt/formatter/pep508.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,25 @@ def _best_effort_string_repr(req: str) -> String:
return toml_string(req)


def normalize_pep508_array(requires_array: Array | None, indent: int) -> None:
def normalize_pep508_array(requires_array: Array | None, indent: int, *, preserve_dependency_versions: bool) -> None:
gaborbernat marked this conversation as resolved.
Show resolved Hide resolved
"""
Normalize a TOML array via PEP-508.

:param requires_array: the input array
:param indent: indentation level
:param preserve_dependency_versions: whether to preserve, and therefore not normalize, requirements
"""
if requires_array is None:
return
# first normalize values
for at in range(len(requires_array)):
normalized = _best_effort_string_repr(normalize_req(str(requires_array[at])))
initial_requirement_string = str(requires_array[at])
if preserve_dependency_versions:
final_requirement_string = initial_requirement_string
else:
final_requirement_string = normalize_req(initial_requirement_string)
gaborbernat marked this conversation as resolved.
Show resolved Hide resolved

gaborbernat marked this conversation as resolved.
Show resolved Hide resolved
normalized = _best_effort_string_repr(req=final_requirement_string)
requires_array[at] = normalized
# then sort
sorted_array(requires_array, indent, key=lambda e: Requirement(e.text).name.lower())
Expand Down
12 changes: 10 additions & 2 deletions src/pyproject_fmt/formatter/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,19 @@ def fmt_project(parsed: TOMLDocument, conf: Config) -> None: # noqa: C901

sorted_array(cast(Optional[Array], project.get("classifiers")), indent=conf.indent, custom_sort="natsort")

normalize_pep508_array(cast(Optional[Array], project.get("dependencies")), conf.indent)
normalize_pep508_array(
requires_array=cast(Optional[Array], project.get("dependencies")),
indent=conf.indent,
preserve_dependency_versions=conf.preserve_dependency_versions,
)
if "optional-dependencies" in project:
opt_deps = cast(Table, project["optional-dependencies"])
for value in opt_deps.values():
normalize_pep508_array(cast(Array, value), conf.indent)
normalize_pep508_array(
requires_array=cast(Array, value),
indent=conf.indent,
preserve_dependency_versions=conf.preserve_dependency_versions,
)
order_keys(opt_deps, (), sort_key=lambda k: k[0]) # pragma: no branch

for of_type in ("scripts", "gui-scripts", "entry-points", "urls"):
Expand Down
28 changes: 28 additions & 0 deletions tests/formatter/test_build_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,31 @@ def test_indent(fmt: Fmt, indent: int) -> None:
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=indent)
fmt(fmt_build_system, config, expected)


def test_preserve_dependency_versions(fmt: Fmt) -> None:
txt = """
[build-system]
requires = [
"A==1.0.0",
]
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=2, preserve_dependency_versions=True)
fmt(fmt_build_system, config, txt)


def test_no_preserve_dependency_versions(fmt: Fmt) -> None:
txt = """
[build-system]
requires = [
"A==1.0.0",
]
"""
expected = """
[build-system]
requires = [
"A==1",
]
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=2, preserve_dependency_versions=False)
fmt(fmt_build_system, config, expected)
22 changes: 21 additions & 1 deletion tests/formatter/test_pep508.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ def test_normalize_pep508_array(indent: int) -> None:
"""
parsed = parse(toml_document_string)
dependencies = parsed["requirements"]
normalize_pep508_array(requires_array=cast(Array, dependencies), indent=indent)
normalize_pep508_array(
requires_array=cast(Array, dependencies),
indent=indent,
preserve_dependency_versions=False,
)
assert dependencies == ["zzz>=1.1.1", "pytest==6"]
expected_string = dedent(
f"""\
Expand All @@ -66,3 +70,19 @@ def test_normalize_pep508_array(indent: int) -> None:
""",
).strip()
assert dependencies.as_string() == expected_string


def test_normalize_pep508_array_preserve_versions() -> None:
toml_document_string = """
requirements = [
"pytest==6.0.0",
]
"""
parsed = parse(toml_document_string)
dependencies = parsed["requirements"]
normalize_pep508_array(
requires_array=cast(Array, dependencies),
indent=2,
preserve_dependency_versions=True,
)
assert dependencies == ["pytest==6.0.0"]
40 changes: 40 additions & 0 deletions tests/formatter/test_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,43 @@ def test_indent(fmt: Fmt, indent: int) -> None:
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=indent)
fmt(fmt_project, config, expected)


def test_preserve_dependency_versions(fmt: Fmt) -> None:
txt = """
[project]
dependencies = [
"A==1.0.0",
]
[project.optional-dependencies]
docs = [
"B==2.0.0",
]
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=2, preserve_dependency_versions=True)
fmt(fmt_project, config, txt)


def test_no_preserve_dependency_versions(fmt: Fmt) -> None:
txt = """
[project]
dependencies = [
"A==1.0.0",
]
[project.optional-dependencies]
docs = [
"B==2.0.0",
]
"""
expected = """
[project]
dependencies = [
"A==1",
]
[project.optional-dependencies]
docs = [
"B==2",
]
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=2, preserve_dependency_versions=False)
fmt(fmt_project, config, expected)
24 changes: 24 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,27 @@ def test_indent(tmp_path: Path, indent: int) -> None:
run(args)
output = pyproject_toml.read_text()
assert output == dedent(expected)


def test_preserve_dependency_versions(tmp_path: Path) -> None:
start = """\
[build-system]
requires = [
"A==1.0.0",
]

[project]
dependencies = [
"A==1.0.0",
]
[project.optional-dependencies]
docs = [
"B==2.0.0",
]
"""
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(dedent(start))
args = [str(pyproject_toml), "--preserve-dependency-versions"]
run(args)
output = pyproject_toml.read_text()
assert output == dedent(start)