Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.bumpversion]
allow_dirty = true
current_version = "0.184.2"
current_version = "0.184.3"

[[tool.bumpversion.files]]
filename = "pyproject.toml"
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"coloredlogs>=15.0.1",
"coverage-conditional-plugin>=0.9.0",
"dycw-pytest-only>=2.1.1",
"dycw-utilities[test]>=0.184.1",
"dycw-utilities[test]>=0.184.2",
"pyright>=1.1.408",
"pytest-cov>=7.0.0",
"pytest-timeout>=2.4.0",
Expand Down Expand Up @@ -116,7 +116,7 @@
name = "dycw-utilities"
readme = "README.md"
requires-python = ">= 3.12"
version = "0.184.2"
version = "0.184.3"

[project.entry-points.pytest11]
pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
Expand Down
32 changes: 28 additions & 4 deletions src/tests/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
_rsync_many_prepare,
_ssh_is_strict_checking_error,
_uv_pip_list_assemble_output,
_UvPipListBaseError,
_UvPipListOutdatedError,
_uv_pip_list_loads,
_UvPipListBaseVersionError,
_UvPipListJsonError,
_UvPipListOutdatedVersionError,
_UvPipListOutput,
append_text,
apt_install_cmd,
Expand Down Expand Up @@ -1776,6 +1778,24 @@ def test_main(self) -> None:
assert is_sequence_of(result, _UvPipListOutput)


class TestUvPipListLoadsOutput:
def test_main(self) -> None:
text = strip_and_dedent("""
[{"name":"name","version":"0.0.1"}]
""")
result = _uv_pip_list_loads(text)
expected = [{"name": "name", "version": "0.0.1"}]
assert result == expected

def test_error(self) -> None:
text = strip_and_dedent("""
[{"name":"name","version":"0.0.1"}]
# warning: The package `name` requires `dep>=1.2.3`, but `1.2.2` is installed
""")
with raises(_UvPipListJsonError, match=r"Unable to parse JSON; got '.*'"):
_ = _uv_pip_list_loads(text)


class TestUvPipListAssembleOutput:
def test_main(self) -> None:
dict_ = {"name": "name", "version": "0.0.1"}
Expand Down Expand Up @@ -1819,13 +1839,17 @@ def test_outdated(self) -> None:
def test_error_base(self) -> None:
dict_ = {"name": "name", "version": "invalid"}
outdated = []
with raises(_UvPipListBaseError, match=r"Unable to parse version; got .*"):
with raises(
_UvPipListBaseVersionError, match=r"Unable to parse version; got .*"
):
_ = _uv_pip_list_assemble_output(dict_, outdated)

def test_error_outdated(self) -> None:
dict_ = {"name": "name", "version": "0.0.1"}
outdated = [{"name": "name", "latest_version": "invalid"}]
with raises(_UvPipListOutdatedError, match=r"Unable to parse version; got .*"):
with raises(
_UvPipListOutdatedVersionError, match=r"Unable to parse version; got .*"
):
_ = _uv_pip_list_assemble_output(dict_, outdated)


Expand Down
2 changes: 1 addition & 1 deletion src/utilities/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 33 additions & 10 deletions src/utilities/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dataclasses import dataclass
from io import StringIO
from itertools import chain, repeat
from json import JSONDecodeError
from pathlib import Path
from re import MULTILINE, escape, search
from shlex import join
Expand Down Expand Up @@ -1784,22 +1785,29 @@ def uv_pip_list(
for outdated in [False, True]
]
text_base, text_outdated = [
run(*cmds, return_=True) for cmds in [cmds_base, cmds_outdated]
]
dicts_base, dicts_outdated = [
json.loads(text) for text in [text_base, text_outdated]
run(*cmds, return_stdout=True) for cmds in [cmds_base, cmds_outdated]
]
dicts_base, dicts_outdated = list(
map(_uv_pip_list_loads, [text_base, text_outdated])
)
return [_uv_pip_list_assemble_output(d, dicts_outdated) for d in dicts_base]


def _uv_pip_list_loads(text: str, /) -> list[StrMapping]:
try:
return json.loads(text)
except JSONDecodeError:
raise _UvPipListJsonError(text=text) from None


def _uv_pip_list_assemble_output(
dict_: StrMapping, outdated: Iterable[StrMapping], /
) -> _UvPipListOutput:
name = dict_["name"]
try:
version = parse_version_2_or_3(dict_["version"])
except ParseVersion2Or3Error:
raise _UvPipListBaseError(data=dict_) from None
raise _UvPipListBaseVersionError(data=dict_) from None
try:
location = Path(dict_["editable_project_location"])
except KeyError:
Expand All @@ -1812,7 +1820,7 @@ def _uv_pip_list_assemble_output(
try:
latest_version = parse_version_2_or_3(outdated_i["latest_version"])
except ParseVersion2Or3Error:
raise _UvPipListOutdatedError(data=outdated_i) from None
raise _UvPipListOutdatedVersionError(data=outdated_i) from None
latest_filetype = outdated_i["latest_filetype"]
return _UvPipListOutput(
name=dict_["name"],
Expand All @@ -1824,7 +1832,20 @@ def _uv_pip_list_assemble_output(


@dataclass(kw_only=True, slots=True)
class UvPipListError(Exception):
class UvPipListError(Exception): ...


@dataclass(kw_only=True, slots=True)
class _UvPipListJsonError(UvPipListError):
text: str

@override
def __str__(self) -> str:
return f"Unable to parse JSON; got {self.text!r}"


@dataclass(kw_only=True, slots=True)
class _UvPipListBaseVersionError(UvPipListError):
data: StrMapping

@override
Expand All @@ -1833,10 +1854,12 @@ def __str__(self) -> str:


@dataclass(kw_only=True, slots=True)
class _UvPipListBaseError(UvPipListError): ...

class _UvPipListOutdatedVersionError(UvPipListError):
data: StrMapping

class _UvPipListOutdatedError(UvPipListError): ...
@override
def __str__(self) -> str:
return f"Unable to parse version; got {self.data}"


def uv_pip_list_cmd(
Expand Down
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading