diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 32d1f80..c77167a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,7 @@ jobs: run: poetry install --extras turbo - name: Run Tests (With Extension Modules) - run: poetry run pytest -q tests + run: poetry run pytest -q tests --turbo=1 - name: Upload coverage to Codecov uses: codecov/codecov-action@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 871effd..c803ed6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [0.2.6] - Unreleased - Added `KY` and `MM` to valid prefixes +- Added support to check for compiled extension modules ## [0.2.5] - 2022-04-10 - Fixed missing `jcs` dependency diff --git a/docs/changelog.md b/docs/changelog.md index 871effd..c803ed6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,7 @@ ## [0.2.6] - Unreleased - Added `KY` and `MM` to valid prefixes +- Added support to check for compiled extension modules ## [0.2.5] - 2022-04-10 - Fixed missing `jcs` dependency diff --git a/iscc_core/check.py b/iscc_core/check.py new file mode 100644 index 0000000..ef4a6d5 --- /dev/null +++ b/iscc_core/check.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +"""Inspect lib environment/installation""" +import importlib.machinery +import inspect + + +EXTENSION_SUFFIXES = tuple(sf.lstrip(".") for sf in importlib.machinery.EXTENSION_SUFFIXES) + + +def suffix(filename): + return "." in filename and filename.rpartition(".")[-1] or "" + + +def isnativemodule(module): + """isnativemodule(thing) → boolean predicate, True if `module` + is a native-compiled (“extension”) module. + + Q.v. this fine StackOverflow answer on this subject: + https://stackoverflow.com/a/39304199/298171 + """ + # Step one: modules only beyond this point: + if not inspect.ismodule(module): # pragma: no cover + return False + + # Step two: return truly when “__loader__” is set: + if isinstance( + getattr(module, "__loader__", None), importlib.machinery.ExtensionFileLoader + ): # pragma: no cover + return True + + # Step three: in leu of either of those indicators, + # check the module path’s file suffix: + try: + ext = suffix(inspect.getfile(module)) + except TypeError as exc: + return "is a built-in" in str(exc) + + return ext in EXTENSION_SUFFIXES diff --git a/tests/conftest.py b/tests/conftest.py index 1656a57..81a5c92 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,17 @@ MB1 = 1024 * 1024 +def pytest_addoption(parser): + parser.addoption( + "--turbo", action="store_true", default=False, help="run extension module tests" + ) + + +@pytest.fixture +def turbo(request): + return request.config.getoption("--turbo") + + @pytest.fixture(scope="module", name="static_bytes") def static_bytes_(n: int = MB1, block_size: int = 4) -> bytes: """Wraps static_bytes function as a fixture (both can be used).""" diff --git a/tests/test_check.py b/tests/test_check.py new file mode 100644 index 0000000..f11f395 --- /dev/null +++ b/tests/test_check.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from iscc_core import cdc, minhash, simhash +from iscc_core import check +import array + + +def test_check_suffix(): + assert check.suffix("hello.world") == "world" + + +def test_check_isnativemodule(): + assert check.isnativemodule(check) is False + assert check.isnativemodule(array) is True + + +def test_check_turbo(turbo): + if turbo is False: + assert check.isnativemodule(cdc) is False + assert check.isnativemodule(simhash) is False + assert check.isnativemodule(minhash) is False + else: + assert check.isnativemodule(cdc) is True + assert check.isnativemodule(simhash) is True + assert check.isnativemodule(minhash) is True