diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1b33b66..01074e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,8 @@ repos: - id: check-yaml - id: end-of-file-fixer exclude: \.changes/.*\.md + - id: no-commit-to-branch + args: [--branch, main] - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema diff --git a/src/pep610/__init__.py b/src/pep610/__init__.py index 6ac0026..e30be72 100644 --- a/src/pep610/__init__.py +++ b/src/pep610/__init__.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +import sys import typing as t from dataclasses import dataclass from importlib.metadata import version @@ -12,6 +13,11 @@ from importlib.metadata import Distribution from os import PathLike + if sys.version_info <= (3, 10): + from typing_extensions import Self + else: + from typing import Self + __version__ = version(__package__) @@ -31,10 +37,16 @@ class VCSInfo: @dataclass -class VCSData: - """VCS direct URL data.""" +class _BaseData: + """Base direct URL data.""" url: str + + +@dataclass +class VCSData(_BaseData): + """VCS direct URL data.""" + vcs_info: VCSInfo @@ -53,10 +65,9 @@ class ArchiveInfo: @dataclass -class ArchiveData: +class ArchiveData(_BaseData): """Archive direct URL data.""" - url: str archive_info: ArchiveInfo @@ -64,14 +75,23 @@ class ArchiveData: class DirInfo: """Local directory information.""" - editable: bool + _editable: bool | None + + @property + def editable(self: Self) -> bool: + """Whether the directory is editable.""" + return self._editable is True + + @editable.setter + def editable(self: Self, value: bool | None) -> None: + """Set whether the directory is editable.""" + self._editable = value @dataclass -class DirData: +class DirData(_BaseData): """Local directory direct URL data.""" - url: str dir_info: DirInfo @@ -101,6 +121,44 @@ def parse(path: PathLike[str]) -> VCSData | ArchiveData | DirData: return result +def to_dict(data: VCSData | ArchiveData | DirData) -> dict[str, t.Any]: + """Convert the parsed data to a dictionary. + + Args: + data: The parsed data. + + Returns: + The data as a dictionary. + """ + result: dict[str, t.Any] = {"url": data.url} + if isinstance(data, VCSData): + vcs_info = { + "vcs": data.vcs_info.vcs, + "commit_id": data.vcs_info.commit_id, + } + if data.vcs_info.requested_revision is not None: + vcs_info["requested_revision"] = data.vcs_info.requested_revision + if data.vcs_info.resolved_revision is not None: + vcs_info["resolved_revision"] = data.vcs_info.resolved_revision + if data.vcs_info.resolved_revision_type is not None: + vcs_info["resolved_revision_type"] = data.vcs_info.resolved_revision_type + result["vcs_info"] = vcs_info + + elif isinstance(data, ArchiveData): + result["archive_info"] = {} + if data.archive_info.hash is not None: + result["archive_info"][ + "hash" + ] = f"{data.archive_info.hash.algorithm}={data.archive_info.hash.value}" + + elif isinstance(data, DirData): + result["dir_info"] = {} + if data.dir_info._editable is not None: # noqa: SLF001 + result["dir_info"]["editable"] = data.dir_info._editable # noqa: SLF001 + + return result + + def _parse(content: str) -> VCSData | ArchiveData | DirData | None: data = json.loads(content) @@ -116,7 +174,7 @@ def _parse(content: str) -> VCSData | ArchiveData | DirData | None: return DirData( url=data["url"], dir_info=DirInfo( - editable=data["dir_info"].get("editable", False), + _editable=data["dir_info"].get("editable"), ), ) diff --git a/tests/test_parse.py b/tests/test_parse.py index a8b478e..9a6a925 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -5,7 +5,17 @@ import pytest -from pep610 import ArchiveData, ArchiveInfo, DirData, DirInfo, HashData, VCSData, VCSInfo, parse +from pep610 import ( + ArchiveData, + ArchiveInfo, + DirData, + DirInfo, + HashData, + VCSData, + VCSInfo, + parse, + to_dict, +) @pytest.mark.parametrize( @@ -15,7 +25,7 @@ {"url": "file:///home/user/project", "dir_info": {"editable": True}}, DirData( url="file:///home/user/project", - dir_info=DirInfo(editable=True), + dir_info=DirInfo(_editable=True), ), id="local_editable", ), @@ -23,7 +33,7 @@ {"url": "file:///home/user/project", "dir_info": {"editable": False}}, DirData( url="file:///home/user/project", - dir_info=DirInfo(editable=False), + dir_info=DirInfo(_editable=False), ), id="local_not_editable", ), @@ -31,7 +41,7 @@ {"url": "file:///home/user/project", "dir_info": {}}, DirData( url="file:///home/user/project", - dir_info=DirInfo(editable=False), + dir_info=DirInfo(_editable=None), ), id="local_no_editable_info", ), @@ -92,4 +102,8 @@ def test_parse(data: dict, expected: object, tmp_path: Path): filepath = tmp_path.joinpath("direct_url.json") with filepath.open("w") as f: json.dump(data, f) - assert parse(filepath) == expected + + result = parse(filepath) + assert result == expected + + assert to_dict(result) == data