Author: Michal Vyskocil <[email protected]>
Branch: 
Changeset: r3195:09ffc07bbde2
Date: 2019-01-08 08:32 +0100
http://bitbucket.org/cffi/cffi/changeset/09ffc07bbde2/

Log:    Increase testing coverage and refactor method names

        Making `pkgconfig.call` function accessible, tests can monkey patch
        it and provide mock. This improves testing, however raised a need to
        give functions better names than `pkgconfig.pkgconfig_kwargs` or
        `pkgconfig.pc`.

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -2,7 +2,7 @@
 from .lock import allocate_lock
 from .error import CDefError
 from . import model
-from .pkgconfig import pkgconfig_installed, merge_dicts, pkgconfig_kwargs
+from . import pkgconfig
 
 try:
     callable
@@ -612,17 +612,12 @@
         if os.sep in module_name or (os.altsep and os.altsep in module_name):
             raise ValueError("'module_name' must not contain '/': use a dotted 
"
                              "name to make a 'package.module' location")
-        if "pkgconfig" in kwds:
-            if pkgconfig_installed ():
-                try:
-                    del kwds ["libraries"]
-                except KeyError:
-                    pass
-                merge_dicts (kwds, pkgconfig_kwargs (kwds ["pkgconfig"]))
-                try:
-                    del kwds ["pkgconfig"]
-                except KeyError:
-                    pass
+        if "pkgconfig" in kwds and pkgconfig.is_installed():
+            if "libraries" in kwds:
+                del kwds["libraries"]  # real library names are going to be
+                                        # provided by pkg-config
+            pkgconfig.merge_flags(kwds, pkgconfig.kwargs(kwds["pkgconfig"]))
+            del kwds["pkgconfig"]
         self._assigned_source = (str(module_name), source,
                                  source_extension, kwds)
 
diff --git a/cffi/pkgconfig.py b/cffi/pkgconfig.py
--- a/cffi/pkgconfig.py
+++ b/cffi/pkgconfig.py
@@ -1,79 +1,86 @@
 # pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ 
integration for cffi
 import subprocess
 
-def pkgconfig_installed ():
-    """Check if pkg=config is installed or not"""
+def is_installed():
+    """Check if pkg-config is installed or not"""
     try:
-        subprocess.check_output (["pkg-config", "--version"])
+        subprocess.check_output(["pkg-config", "--version"])
         return True
     except subprocess.CalledProcessError:
         return False
 
-def merge_dicts (d1, d2):
-    """Helper function to merge two dicts with lists"""
-    for key, value in d2.items ():
-        if not key in d1:
-            d1 [key] = value
+
+def merge_flags(cfg1, cfg2):
+    """Merge values from cffi config flags cfg2 to cf1
+
+    Example:
+        merge_flags({"libraries": ["one"]}, {"libraries": "two"})
+        {"libraries}" : ["one", "two"]}
+    """
+    for key, value in cfg2.items():
+        if not key in cfg1:
+            cfg1 [key] = value
         else:
-            d1 [key].extend (value)
-    return d1
+            cfg1 [key].extend(value)
+    return cfg1
 
-def pkgconfig_kwargs (libs):
-    r"""Return kwargs for FFI.set_source based on pkg-config output
+
+def call(libname, flag):
+    """Calls pkg-config and returing the output"""
+    a = ["pkg-config", "--print-errors"]
+    a.append(flag)
+    a.append(libname)
+    return subprocess.check_output(a)
+
+
+def flags(libs):
+    r"""Return compiler line flags for FFI.set_source based on pkg-config 
output
 
     Usage
         ...
-        ffibuilder.set_source ("_foo", libraries = ["foo", "bar"], pkgconfig = 
["libfoo", "libbar"])
+        ffibuilder.set_source("_foo", libraries = ["foo", "bar"], pkgconfig = 
["libfoo", "libbar"])
 
-    If pkg-config is installed on build machine, then arguments include_dirs,
-    library_dirs and define_macros are extended with an output of pkg-config
-    [command] libfoo and pkgconfig [command] libbar. Argument libraries is
-    replaced by an output of pkgconfig --libs-only-l calls.
+    If `pkg-config` is installed on build machine, then arguments
+    `include_dirs`, `library_dirs`, `libraries`, `define_macros`,
+    `extra_compile_args` and `extra_link_args` are extended with an output of
+    `pkg-config` for `libfoo` and `libbar`.
     """
 
     # make API great again!
-    if isinstance (libs, (str, bytes)):
+    if isinstance(libs, (str, bytes)):
         libs = (libs, )
     
     # drop starting -I -L -l from cflags
-    def dropILl (string):
-        def _dropILl (string):
-            if string.startswith (b"-I") or string.startswith (b"-L") or 
string.startswith (b"-l"):
+    def dropILl(string):
+        def _dropILl(string):
+            if string.startswith(b"-I") or string.startswith(b"-L") or 
string.startswith(b"-l"):
                 return string [2:]
-        return [_dropILl (x) for x in string.split ()]
+        return [_dropILl(x) for x in string.split()]
 
     # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by cffi
-    def macros (string):
-        def _macros (string):
-            return tuple (string [2:].split ('=', 2))
-        return [_macros (x) for x in string.split () if x.startswith ("-D")]
+    def macros(string):
+        def _macros(string):
+            return tuple(string [2:].split(b"=", 2))
+        return [_macros(x) for x in string.split() if x.startswith(b"-D")]
 
-    def drop_macros (string):
-        return [x for x in string.split () if not x.startswith ("-D")]
-
-    # pkg-config call
-    def pc (libname, *args):
-        a = ["pkg-config", "--print-errors"]
-        a.extend (args)
-        a.append (libname)
-        return subprocess.check_output (a)
+    def drop_macros(string):
+        return [x for x in string.split() if not x.startswith(b"-D")]
 
     # return kwargs for given libname
-    def kwargs (libname):
+    def kwargs(libname):
         return {
-                "include_dirs" : dropILl (pc (libname, "--cflags-only-I")),
-                "library_dirs" : dropILl (pc (libname, "--libs-only-L")),
-                "libraries" : dropILl (pc (libname, "--libs-only-l")),
-                "define_macros" : macros (pc (libname, "--cflags-only-other")),
-                "extra_compile_args" : drop_macros (pc (libname, 
"--cflags-only-other")),
-                "extra_link_args" : pc (libname, "--libs-only-other").split ()
+                "include_dirs" : dropILl(call(libname, "--cflags-only-I")),
+                "library_dirs" : dropILl(call(libname, "--libs-only-L")),
+                "libraries" : dropILl(call(libname, "--libs-only-l")),
+                "define_macros" : macros(call(libname, "--cflags-only-other")),
+                "extra_compile_args" : drop_macros(call(libname, 
"--cflags-only-other")),
+                "extra_link_args" : call(libname, "--libs-only-other").split()
                 }
 
     # merge all arguments together
     ret = {}
     for libname in libs:
-        foo = kwargs (libname)
-        merge_dicts (ret, foo)
+        foo = kwargs(libname)
+        merge_flags(ret, foo)
 
     return ret
-
diff --git a/testing/cffi1/test_pkgconfig.py b/testing/cffi1/test_pkgconfig.py
--- a/testing/cffi1/test_pkgconfig.py
+++ b/testing/cffi1/test_pkgconfig.py
@@ -1,30 +1,43 @@
 import sys
 import subprocess
 import py
-from cffi.pkgconfig import pkgconfig_installed, merge_dicts, pkgconfig_kwargs
+import cffi.pkgconfig as pkgconfig
 
-def test_merge_dicts ():
+def mock_call(libname, flag):
+    assert libname=="python-3.6", "mocked pc function supports python-3.6 
input ONLY"
+
+    flags = {
+        "--cflags-only-I": b"-I/usr/include/python3.6m\n",
+        "--libs-only-L": b"-L/usr/lib64\n",
+        "--libs-only-l": b"-lpython3.6\n",
+        "--cflags-only-other": b"-DCFFI_TEST=1 -O42\n",
+        "--libs-only-other": b"-lm\n",
+    }
+    return flags[flag]
+
+pkgconfig.call = mock_call
+
+
+def test_merge_flags():
 
     d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []}
     d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]}
 
-    merge_dicts (d1, d2)
+    pkgconfig.merge_flags(d1, d2)
     assert d1 == {
         "ham": [1, 2, 3],
         "spam" : ["a", "b", "c", "spam", "spam", "spam"],
         "bar" : ["b", "a", "z"],
         "foo" : []}
 
-def test_pkgconfig ():
-    if not pkgconfig_installed:
-        py.test.skip ("pkg-config is not installed on the system")
 
-    version = sys.version_info.major
-    kwargs = {}
-    try:
-        kwargs = pkgconfig_kwargs ("python%s" % version)
-    except subprocess.CalledProcessError as e:
-        py.test.skip ("No python%s pkg-config file installed" % version)
-    
-    assert any (b"python" in lib for lib in kwargs ["libraries"]) == True
-    assert any (b"python" in dir for dir in kwargs ["include_dirs"]) == True
+def test_pkgconfig():
+    kwargs = pkgconfig.flags("python-3.6")
+    assert kwargs == {
+        'include_dirs': [b'/usr/include/python3.6m'],
+        'library_dirs': [b'/usr/lib64'],
+        'libraries': [b'python3.6'],
+        'define_macros': [(b'CFFI_TEST', b'1')],
+        'extra_compile_args': [b'-O42'],
+        'extra_link_args': [b'-lm']
+    }
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to