diff --git a/src/pkgcraft/C.pxd b/src/pkgcraft/C.pxd index 842e368..26d0335 100644 --- a/src/pkgcraft/C.pxd +++ b/src/pkgcraft/C.pxd @@ -1110,6 +1110,14 @@ cdef extern from "pkgcraft.h": # The argument must be a non-null Eapi pointer. char **pkgcraft_eapi_metadata_keys(const Eapi *eapi, uintptr_t *len) + # Determine if a string is a valid EAPI. + # + # Returns NULL on error. + # + # # Safety + # The argument should point to a UTF-8 string. + const char *pkgcraft_eapi_parse(const char *s) + # Get all known EAPIS. # # # Safety diff --git a/src/pkgcraft/dep/version.pyx b/src/pkgcraft/dep/version.pyx index 20d1e30..9bf08e7 100644 --- a/src/pkgcraft/dep/version.pyx +++ b/src/pkgcraft/dep/version.pyx @@ -146,7 +146,7 @@ cdef class Version: def parse(s: str, raised=False): """Determine if a string is a valid package version. - This avoids any allocations, only returning the validity status. + This avoids any string allocations, only returning the validity status. Args: s: the string to parse diff --git a/src/pkgcraft/eapi.pyx b/src/pkgcraft/eapi.pyx index b7e73ba..99fbcea 100644 --- a/src/pkgcraft/eapi.pyx +++ b/src/pkgcraft/eapi.pyx @@ -113,6 +113,33 @@ cdef class Eapi(Indirect): """Try to convert an object to an Eapi object.""" return Eapi._from_obj(obj) + @staticmethod + def parse(s: str, raised=False): + """Determine if a string is a valid EAPI. + + This avoids any string allocations, only returning the validity status. + + Args: + s: the string to parse + raised: if True, raise an exception when invalid + + Returns: + bool: True if the given string represents a valid EAPI, otherwise False. + + Raises: + PkgcraftError: on failure if the raised parameter is set to True + + >>> from pkgcraft.eapi import Eapi + >>> Eapi.parse('01') + True + >>> Eapi.parse('@1') + False + """ + valid = C.pkgcraft_eapi_parse(s.encode()) is not NULL + if not valid and raised: + raise PkgcraftError + return valid + def has(self, s: str): """Check if an EAPI has a given feature. diff --git a/tests/test_eapi.py b/tests/test_eapi.py index f80b674..59dacab 100644 --- a/tests/test_eapi.py +++ b/tests/test_eapi.py @@ -3,6 +3,7 @@ import pytest from pkgcraft.eapi import * +from pkgcraft.error import PkgcraftError from .misc import OperatorMap @@ -22,6 +23,13 @@ def test_globals(): class TestEapi: + def test_parse(self): + assert Eapi.parse("01") + for s in ("@1", "-1", ".1"): + assert not Eapi.parse(s) + with pytest.raises(PkgcraftError, match=f"invalid EAPI: {s}"): + Eapi.parse(s, raised=True) + def test_has(self): assert not EAPI_LATEST_OFFICIAL.has("RepoIds") assert EAPI_LATEST.has("RepoIds")