33###########################################################################
44import os
55import sys
6+ from importlib .metadata import PackageNotFoundError , metadata
67from pathlib import Path
78
89import pytest
910
1011
12+ def xfail_if_not_installed (package_name ):
13+ """A test decorator that xfails a test if the named package isn't installed.
14+ The third-party tests are dependant on packages being built. During pre-release some
15+ packages won't be compilable. So - the pyproject.toml installs third party packages
16+ with some conditional gating.
17+
18+ This decorator checks for app metadata (which is an indicator that the package has
19+ been installed). If the metadata exists, the test is executed; if it isn't we XFAIL
20+ the test because it *can't* pass.
21+ """
22+
23+ def _xfail_if_not_installed (fn ):
24+ def _testfunc (* args , ** kwargs ):
25+ try :
26+ metadata (package_name )
27+ except PackageNotFoundError :
28+ pytest .xfail (f"{ package_name } is not installed" )
29+
30+ # Actually run the test
31+ fn (* args , ** kwargs )
32+
33+ return _testfunc
34+
35+ return _xfail_if_not_installed
36+
37+
38+ @xfail_if_not_installed ("pillow" )
1139def test_module_paths ():
1240 "Third party binary modules have meaningful __file__ attributes"
1341 import PIL
@@ -22,6 +50,7 @@ def test_module_paths():
2250
2351
2452@pytest .mark .skipif (sys .platform == "win32" , reason = "cffi not available on windows" )
53+ @xfail_if_not_installed ("cffi" )
2554def test_cffi ():
2655 "CFFI can be used as an alternative FFI interface"
2756 from cffi import FFI
@@ -32,6 +61,7 @@ def test_cffi():
3261 assert lib .strlen (ffi .new ("char[]" , b"hello world" )) == 11
3362
3463
64+ @xfail_if_not_installed ("cryptography" )
3565def test_cryptography ():
3666 "The cryptography module can be used"
3767 # Cryptography is a common binary library that uses cffi and OpenSSL internally
@@ -87,6 +117,7 @@ def test_cryptography():
87117 assert "www.android.com" == domain
88118
89119
120+ @xfail_if_not_installed ("lru-dict" )
90121def test_lru_dict ():
91122 "The LRUDict binary module can be used"
92123 # lru-dict is the simplest possible example of a third-party module.
@@ -107,6 +138,7 @@ def test_lru_dict():
107138 assert lru_dict [f"item_{ i } " ] == i
108139
109140
141+ @xfail_if_not_installed ("pillow" )
110142def test_pillow ():
111143 "Pillow can be used to load images"
112144 # Pillow is a module that has dependencies on other libraries (libjpeg, libft2)
@@ -122,6 +154,7 @@ def test_pillow():
122154 image .close ()
123155
124156
157+ @xfail_if_not_installed ("numpy" )
125158def test_numpy ():
126159 "Numpy Arrays can be created"
127160 from numpy import array
@@ -130,6 +163,7 @@ def test_numpy():
130163 assert [4 , 7 ] == (array ([1 , 2 ]) + array ([3 , 5 ])).tolist ()
131164
132165
166+ @xfail_if_not_installed ("pandas" )
133167def test_pandas ():
134168 "Pandas DataFrames can be created"
135169 from pandas import DataFrame , __version__
0 commit comments