Skip to content

Commit

Permalink
Add option to skip normalising requirement versions (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamtheturtle committed Nov 1, 2023
1 parent ba214ba commit 335e657
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 7 deletions.
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
keep_full_version: 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,
keep_full_version=self.keep_full_version,
)
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 = "keep full dependency versions. For example do not change version 1.0.0 to 1"
group.add_argument("--keep-full-version", action="store_true", help=msg)
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,
keep_full_version=conf.keep_full_version,
)
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
keep_full_version: bool = False


__all__ = [
Expand Down
7 changes: 5 additions & 2 deletions src/pyproject_fmt/formatter/pep508.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,21 @@ 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, *, keep_full_version: bool) -> None:
"""
Normalize a TOML array via PEP-508.
:param requires_array: the input array
:param indent: indentation level
:param keep_full_version: 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])
req_string = initial_requirement_string if keep_full_version else normalize_req(initial_requirement_string)
normalized = _best_effort_string_repr(req=req_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,
keep_full_version=conf.keep_full_version,
)
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,
keep_full_version=conf.keep_full_version,
)
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_keep_full_version_on(fmt: Fmt) -> None:
txt = """
[build-system]
requires = [
"A==1.0.0",
]
"""
config = Config(pyproject_toml=Path(), toml=dedent(txt), indent=2, keep_full_version=True)
fmt(fmt_build_system, config, txt)


def test_keep_full_version_off(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, keep_full_version=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,
keep_full_version=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_keep_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,
keep_full_version=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_keep_full_version_on(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, keep_full_version=True)
fmt(fmt_project, config, txt)


def test_keep_full_version_off(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, keep_full_version=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_keep_full_version_cli(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), "--keep-full-version"]
run(args)
output = pyproject_toml.read_text()
assert output == dedent(start)

0 comments on commit 335e657

Please sign in to comment.