From 6723a4e795bc866f4b083772af63379dbed4e98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= <16805946+edgarrmondragon@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:05:33 -0600 Subject: [PATCH 1/2] refactor: Make importlib-resources a dev dependency and remove the `SCHEMA_FILE` constant from the public API (#36) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- 📚 Documentation preview 📚: https://pep610--36.org.readthedocs.build/en/36/ --- pyproject.toml | 2 +- src/pep610/__init__.py | 8 +------- {src/pep610 => tests/fixtures}/direct_url.schema.json | 0 tests/test_generic.py | 9 ++++++++- 4 files changed, 10 insertions(+), 9 deletions(-) rename {src/pep610 => tests/fixtures}/direct_url.schema.json (100%) diff --git a/pyproject.toml b/pyproject.toml index 6d8de1c..6a65992 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,12 +34,12 @@ dynamic = [ "version", ] dependencies = [ - 'importlib-resources>=5.3; python_version < "3.9"', ] optional-dependencies.dev = [ "coverage[toml]>=6.5", "hypothesis", "hypothesis-jsonschema", + 'importlib-resources>=5.3; python_version < "3.9"', "pytest", ] optional-dependencies.docs = [ diff --git a/src/pep610/__init__.py b/src/pep610/__init__.py index 19bc8ab..5f055d7 100644 --- a/src/pep610/__init__.py +++ b/src/pep610/__init__.py @@ -4,18 +4,13 @@ import hashlib import json -import sys import typing as t from dataclasses import dataclass from functools import singledispatch from importlib.metadata import version -if sys.version_info < (3, 9): - import importlib_resources -else: - import importlib.resources as importlib_resources - if t.TYPE_CHECKING: + import sys from importlib.metadata import Distribution, PathDistribution if sys.version_info <= (3, 10): @@ -46,7 +41,6 @@ "write_to_distribution", ] -SCHEMA_FILE = importlib_resources.files(__package__) / "direct_url.schema.json" __version__ = version(__package__) diff --git a/src/pep610/direct_url.schema.json b/tests/fixtures/direct_url.schema.json similarity index 100% rename from src/pep610/direct_url.schema.json rename to tests/fixtures/direct_url.schema.json diff --git a/tests/test_generic.py b/tests/test_generic.py index 36f5969..95d2d70 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -1,12 +1,19 @@ import json +import sys from importlib.metadata import Distribution import pytest from hypothesis import HealthCheck, given, settings from hypothesis_jsonschema import from_schema -from pep610 import SCHEMA_FILE, read_from_distribution, write_to_distribution +from pep610 import read_from_distribution, write_to_distribution +if sys.version_info < (3, 9): + import importlib_resources +else: + import importlib.resources as importlib_resources + +SCHEMA_FILE = importlib_resources.files(__package__) / "fixtures/direct_url.schema.json" SCHEMA = json.loads(SCHEMA_FILE.read_text()) From dddc740bc5d80cc7ec70ed72b3e8fbfdc537b3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= <16805946+edgarrmondragon@users.noreply.github.com> Date: Mon, 5 Feb 2024 19:08:24 -0600 Subject: [PATCH 2/2] feat: Add `is_editable` wrapper function (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- 📚 Documentation preview 📚: https://pep610--37.org.readthedocs.build/en/37/ --- .readthedocs.yaml | 2 +- docs/index.md | 4 ++++ src/pep610/__init__.py | 27 +++++++++++++++++++++- tests/test_parse.py | 52 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1bd401d..fd319be 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" jobs: post_checkout: - git fetch --unshallow || true diff --git a/docs/index.md b/docs/index.md index dccc63a..a1e1e29 100644 --- a/docs/index.md +++ b/docs/index.md @@ -83,3 +83,7 @@ else: ```{eval-rst} .. autofunction:: pep610.read_from_distribution ``` + +```{eval-rst} +.. autofunction:: pep610.is_editable +``` diff --git a/src/pep610/__init__.py b/src/pep610/__init__.py index 5f055d7..dc1835d 100644 --- a/src/pep610/__init__.py +++ b/src/pep610/__init__.py @@ -7,7 +7,7 @@ import typing as t from dataclasses import dataclass from functools import singledispatch -from importlib.metadata import version +from importlib.metadata import distribution, version if t.TYPE_CHECKING: import sys @@ -325,6 +325,11 @@ def read_from_distribution(dist: Distribution) -> VCSData | ArchiveData | DirDat Returns: The parsed PEP 610 file. + + >>> import importlib.metadata + >>> dist = importlib.metadata.distribution("pep610") + >>> read_from_distribution(dist) # doctest: +SKIP + DirData(url='file:///home/user/pep610', dir_info=DirInfo(editable=False)) """ if contents := dist.read_text("direct_url.json"): return _parse(contents) @@ -332,6 +337,26 @@ def read_from_distribution(dist: Distribution) -> VCSData | ArchiveData | DirDat return None +def is_editable(distribution_name: str) -> bool: + """Wrapper around :func:`read_from_distribution` to check if a distribution is editable. + + Args: + distribution_name: The distribution name. + + Returns: + Whether the distribution is editable. + + Raises: + importlib_metadata.PackageNotFoundError: If the distribution is not found. + + >>> is_editable("pep610") # doctest: +SKIP + False + """ # noqa: DAR402, RUF100 + dist = distribution(distribution_name) + data = read_from_distribution(dist) + return isinstance(data, DirData) and data.dir_info.is_editable() + + def write_to_distribution(dist: PathDistribution, data: dict) -> int: """Write the direct URL data to a distribution. diff --git a/tests/test_parse.py b/tests/test_parse.py index 292abef..2b19f6a 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -15,6 +15,7 @@ HashData, VCSData, VCSInfo, + is_editable, read_from_distribution, to_dict, write_to_distribution, @@ -321,3 +322,54 @@ def test_no_file(tmp_path: Path): """Test that a missing file is read back as None.""" dist = Distribution.at(tmp_path) assert read_from_distribution(dist) is None + + +@pytest.mark.parametrize( + ("data", "expected"), + [ + pytest.param( + { + "url": "file:///home/user/project", + "dir_info": {"editable": True}, + }, + True, + id="editable", + ), + pytest.param( + { + "url": "file:///home/user/project", + "dir_info": {"editable": False}, + }, + False, + id="not_editable", + ), + pytest.param( + { + "url": "file:///home/user/project", + "dir_info": {}, + }, + False, + id="no_editable_info", + ), + pytest.param( + { + "url": "https://github.com/pypa/pip.git", + "vcs_info": { + "vcs": "git", + "requested_revision": "1.3.1", + "resolved_revision_type": "tag", + "commit_id": "7921be1537eac1e97bc40179a57f0349c2aee67d", + }, + }, + False, + id="vcs_git", + ), + ], +) +def test_is_editable(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, data: dict, expected: bool): # noqa: FBT001 + """Test the is_editable function.""" + dist = Distribution.at(tmp_path) + write_to_distribution(dist, data) + + monkeypatch.setattr("pep610.distribution", lambda _: dist) + assert is_editable("my_package") is expected