Skip to content

Commit

Permalink
GHA CI dependencies x 7.
Browse files Browse the repository at this point in the history
This commit is the next in a commit chain improving our GitHub
Actions-based continuous integration (CI) configuration to install
optional test-time dependencies. Specifically, this commit attempts to
circumvent installation woes induced by Apple's patently broken
"Accelerate" BLAS replacement (as documented at numpy/numpy#15947) by
conditionally avoiding installation of `pip` packages built against
"Accelerate" under PyPy. Whereas forcing `pip` to reinstall these
packages with `--force-reinstall` succeeds under CPython, the same
approach fails to improve matters under PyPy for unknown reasons. We are
short on sanity and even shorter on time, so the only remaining option
is to nuke these packages from orbit under macOS + PyPy -- which is such
an outlier edge-case to begin with that it seems doubtful anyone will
care. We care, of course. But you can only do so much when your core
platform is fundamentally broken. Thanks, Apple. (*Drip-fed metalhead!*)
  • Loading branch information
leycec committed Aug 6, 2021
1 parent f346535 commit 7f1fc19
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 16 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/python_test.yml
Expand Up @@ -241,8 +241,10 @@ jobs:
#
# Sadly, the "env:" map only locally exports the environment
# variables it declares to the current step. Thanks, GitHub Actions.
[[ ${{ matrix.platform }} == 'macos-latest' ]] &&
if [[ ${{ matrix.platform }} == 'macos-latest' ]]; then
export _TOX_PIP_INSTALL_OPTIONS='--force-reinstall'
echo "Massaging macOS dependencies with \"pip install ${_TOX_PIP_INSTALL_OPTIONS}\"..."
fi
# Dismantled, this is:
# * "--skip-missing-interpreters=false" disables the corresponding
# "skip_missing_interpreters = true" setting globally enabled by
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -166,7 +166,7 @@ Let's install ``beartype`` with Anaconda_:
conda install beartype
Commemorate this special moment with |bear-ified|, `our overbearing project
shield <Badge_>`__. What says quality like `a bear on a badge <Badge_>`__?
shield <Badge_>`__. Nothing shouts quality like `a bear on a badge <Badge_>`__.
Platform
--------
Expand Down
Empty file added beartype/_util/os/__init__.py
Empty file.
30 changes: 30 additions & 0 deletions beartype/_util/os/utilostest.py
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
# --------------------( LICENSE )--------------------
# Copyright (c) 2014-2021 Beartype authors.
# See "LICENSE" for further details.

'''
Project-wide **platform tester** (i.e., functions detecting the current
platform the active Python interpreter is running under) utilities.
This private submodule is *not* intended for importation by downstream callers.
'''

# ....................{ IMPORTS }....................
from beartype._util.cache.utilcachecall import callable_cached
from platform import system

# See the "beartype.cave" submodule for further commentary.
__all__ = ['STAR_IMPORTS_CONSIDERED_HARMFUL']

# ....................{ TESTERS }....................
@callable_cached
def is_os_macos() -> bool:
'''
``True`` only if the current platform is **Apple macOS**, the operating
system previously known as "OS X."
This tester is memoized for efficiency.
'''

return system() == 'Darwin'
18 changes: 10 additions & 8 deletions beartype/_util/py/utilpyinterpreter.py
Expand Up @@ -10,17 +10,19 @@
'''

# ....................{ IMPORTS }....................
from beartype._util.cache.utilcachecall import callable_cached
from platform import python_implementation

# See the "beartype.cave" submodule for further commentary.
__all__ = ['STAR_IMPORTS_CONSIDERED_HARMFUL']

# ....................{ TESTERS }....................
#FIXME: Inefficient. Just wrap this in a cached function call instead: e.g.,
# @callable_cached
# def is_pypy() -> bool:
# return python_implementation() == 'PyPy'
IS_PYPY = python_implementation() == 'PyPy'
'''
``True`` only if the current Python interpreter is PyPy.
'''
@callable_cached
def is_py_pypy() -> bool:
'''
``True`` only if the active Python interpreter is **PyPy**.
This tester is memoized for efficiency.
'''

return python_implementation() == 'PyPy'
38 changes: 34 additions & 4 deletions beartype/meta.py
Expand Up @@ -37,7 +37,8 @@
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

import sys as _sys
from beartype._util.py.utilpyinterpreter import IS_PYPY as _IS_PYPY
from beartype._util.os.utilostest import is_os_macos as _is_os_macos
from beartype._util.py.utilpyinterpreter import is_py_pypy as _is_py_pypy
from typing import Tuple as _Tuple

# See the "beartype.cave" submodule for further commentary.
Expand Down Expand Up @@ -331,16 +332,45 @@ def _convert_version_str_to_tuple(version_str: str) -> _Tuple[int, ...]:
# *NOT* supported by newer versions of these dependencies.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
LIBS_TESTTIME_OPTIONAL = (
'numpy',
'typing_extensions',
) + (
# If the active Python interpreter is *NOT* PyPy and thus supports mypy...
# If the active Python interpreter is *NOT* PyPy...
(
# mypy >= 0.800, a reasonably recent version known to behave well. Even
# less reasonably recent versions of mypy are significantly deficient
# with respect to error reporting and *MUST* thus be blacklisted.
'mypy >=0.800' ,
) if not _IS_PYPY else
# If the current platform is *NOT* macOS...
(
# NumPy. NumPy has become *EXTREMELY* non-trivial to install under
# macOS with "pip", due to the conjunction of multiple issues:
# * NumPy > 1.18.0, whose initial importation now implicitly
# detects whether the BLAS implementation NumPy was linked
# against is sane and raises a "RuntimeError" exception if that
# implementation is insane resembling:
# RuntimeError: Polyfit sanity test emitted a warning, most
# likely due to using a buggy Accelerate backend. If you
# compiled yourself, more information is available at
# https://numpy.org/doc/stable/user/building.html#accelerated-blas-lapack-libraries
# Otherwise report this to the vendor that provided NumPy.
# RankWarning: Polyfit may be poorly conditioned
# * Apple's blatantly broken multithreaded implementation of their
# "Accelerate" BLAS replacement, which neither NumPy nor "pip"
# have *ANY* semblance of control over.
# * "pip" under PyPy, which for unknown reasons fails to properly
# install NumPy even when the "--force-reinstall" option is
# explicitly passed to "pip". Oddly, passing that option to "pip"
# under CPython resolves this issue -- which is why we only
# selectively disable NumPy installation under macOS + PyPy.
#
# See also this upstream NumPy issue:
# https://github.com/numpy/numpy/issues/15947
'numpy',
) if not _is_os_macos() else
# Else, the active Python interpreter is PyPy under macOS and thus
# fails to support NumPy. In this case, avoid requiring NumPy.
()
) if not _is_py_pypy() else
# Else, the active Python interpreter is PyPy and thus fails to support
# mypy. In this case, avoid requiring mypy. See also this official
# documentation discussing mypy's current incompatibility with PyPy:
Expand Down
Empty file.
30 changes: 30 additions & 0 deletions beartype_test/a00_unit/a00_util/os/test_utilostest.py
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
# --------------------( LICENSE )--------------------
# Copyright (c) 2014-2021 Beartype authors.
# See "LICENSE" for further details.

'''
Project-wide **platform tester** unit tests.
This submodule unit tests the public API of the private
:mod:`beartype._util.os.utilostest` submodule.
'''

# ....................{ IMPORTS }....................
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# WARNING: To raise human-readable test errors, avoid importing from
# package-specific submodules at module scope.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

# ....................{ TESTS ~ tester }....................
def test_is_os_macos() -> None:
'''
Test the :func:`beartype._util.os.utilostest.is_os_macos` tester.
'''

# Defer heavyweight imports.
from beartype._util.os.utilostest import is_os_macos

# Assert this tester returns a boolean.
IS_OS_MACOS = is_os_macos()
assert isinstance(IS_OS_MACOS, bool)
30 changes: 30 additions & 0 deletions beartype_test/a00_unit/a00_util/py/test_utilpyinterpreter.py
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
# --------------------( LICENSE )--------------------
# Copyright (c) 2014-2021 Beartype authors.
# See "LICENSE" for further details.

'''
Project-wide **Python interpreter** unit tests.
This submodule unit tests the public API of the private
:mod:`beartype._util.py.utilpyinterpreter` submodule.
'''

# ....................{ IMPORTS }....................
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# WARNING: To raise human-readable test errors, avoid importing from
# package-specific submodules at module scope.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

# ....................{ TESTS ~ tester }....................
def test_is_py_pypy() -> None:
'''
Test the :func:`beartype._util.py.utilpyinterpreter.is_py_pypy` tester.
'''

# Defer heavyweight imports.
from beartype._util.py.utilpyinterpreter import is_py_pypy

# Assert this tester returns a boolean.
IS_PY_PYPY = is_py_pypy()
assert isinstance(IS_PY_PYPY, bool)
4 changes: 2 additions & 2 deletions beartype_test/util/mark/pytskip.py
Expand Up @@ -119,10 +119,10 @@ def skip_if_pypy():
'''

# Defer heavyweight imports.
from beartype._util.py.utilpyinterpreter import IS_PYPY
from beartype._util.py.utilpyinterpreter import is_py_pypy

# Skip this test if the active Python interpreter is PyPy.
return skip_if(IS_PYPY, reason='Incompatible with PyPy.')
return skip_if(is_py_pypy(), reason='Incompatible with PyPy.')


def skip_if_python_version_greater_than_or_equal_to(version: str):
Expand Down

0 comments on commit 7f1fc19

Please sign in to comment.