#!/usr/bin/env python3 # Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) import _imp import distutils.sysconfig import importlib.machinery import os import tempfile import unittest from distutils.core import setup from distutils.dist import Distribution from distutils.extension import Extension class DistutilsModuleTest(unittest.TestCase): def test_sysconfig_get_python_inc_returns_string(self): python_inc = distutils.sysconfig.get_python_inc() self.assertTrue(os.path.isdir(python_inc)) self.assertTrue(os.path.isfile(os.path.join(python_inc, "Python.h"))) def test_sysconfig_get_python_lib_returns_string(self): python_lib = distutils.sysconfig.get_python_lib() self.assertIn("site-packages", python_lib) def test_build_ext_with_c_file_creates_library(self): with tempfile.TemporaryDirectory() as dir_path: source_dir = f"{dir_path}/src" build_dir = f"{dir_path}/build" os.makedirs(source_dir) os.makedirs(build_dir) file_path = f"{source_dir}/foo.c" with open(file_path, "w") as fp: fp.write( """\ #include "Python.h" PyObject *func(PyObject *a0, PyObject *a1) { (void)a0; (void)a1; return PyUnicode_FromString("and now for something completely different"); } static PyMethodDef methods[] = { {"announce", func, METH_NOARGS, "bar docu"}, {NULL, NULL}, }; static PyModuleDef def = { PyModuleDef_HEAD_INIT, "foo", NULL, 0, methods, }; PyMODINIT_FUNC PyInit_foo(void) { return PyModule_Create(&def); } """ ) self.assertEqual(len(os.listdir(source_dir)), 1) # Setup compilation settings ext = Extension(name="foo", sources=[file_path]) self.assertIsInstance(ext, Extension) # Compile C File dist = setup( name="test_so_compilation", ext_modules=[ext], script_args=["--quiet", "build_ext", "--build-temp", build_dir], options={"build_ext": {"build_lib": source_dir}}, ) self.assertIsInstance(dist, Distribution) # Check directory contents dir_contents = sorted(os.listdir(source_dir)) self.assertEqual(len(dir_contents), 2) self.assertTrue(dir_contents[0].endswith(".c")) self.assertTrue(dir_contents[1].endswith(".so")) lib_file = f"{source_dir}/{dir_contents[1]}" spec = importlib.machinery.ModuleSpec("foo", None, origin=lib_file) module = _imp.create_dynamic(spec) self.assertEqual( module.announce(), "and now for something completely different" ) def test_build_ext_with_cpp_file_creates_library(self): with tempfile.TemporaryDirectory() as dir_path: source_dir = f"{dir_path}/src" build_dir = f"{dir_path}/build" os.makedirs(source_dir) os.makedirs(build_dir) file_path = f"{source_dir}/foo.cpp" with open(file_path, "w") as fp: fp.write( """\ #include #include "Python.h" PyObject* func(PyObject*, PyObject*) { std::stringstream ss; ss << "Hello" << ' ' << "world"; return PyUnicode_FromString(ss.str().c_str()); } static PyMethodDef methods[] = { {"greet", func, METH_NOARGS, "bar docu"}, {nullptr, nullptr}, }; static PyModuleDef def = { PyModuleDef_HEAD_INIT, "foo", nullptr, 0, methods, }; PyMODINIT_FUNC PyInit_foo() { return PyModule_Create(&def); } """ ) self.assertEqual(len(os.listdir(source_dir)), 1) # Setup compilation settings ext = Extension(name="foo", sources=[file_path]) self.assertIsInstance(ext, Extension) dist = setup( name="test_so_compilation", ext_modules=[ext], script_args=["--quiet", "build_ext", "--build-temp", build_dir], options={"build_ext": {"build_lib": source_dir}}, ) self.assertIsInstance(dist, Distribution) # Check directory contents dir_contents = sorted(os.listdir(source_dir)) self.assertEqual(len(dir_contents), 2) self.assertTrue(dir_contents[0].endswith(".cpp")) self.assertTrue(dir_contents[1].endswith(".so")) lib_file = f"{source_dir}/{dir_contents[1]}" spec = importlib.machinery.ModuleSpec("foo", None, origin=lib_file) module = _imp.create_dynamic(spec) self.assertEqual(module.greet(), "Hello world") if __name__ == "__main__": unittest.main()