diff --git a/.gitignore b/.gitignore index fd2939f..41318a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ # Build directory build docs/_build +tests/bin # Python *.egg-info __pycache__ +.eggs # VS Code .vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 744efea..2e9477f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8.12) project(python_cpp_example) -SET(SOURCE_DIR "python_cpp_example") +SET(SOURCE_DIR "src/python_cpp_example") # Tell cmake that headers are in alse in source_dir include_directories(${SOURCE_DIR}) SET(SOURCES "${SOURCE_DIR}/math.cpp") diff --git a/README.md b/README.md index edc90a7..a218666 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # python_cpp_example + This repository contains an example Python module which wraps C++ code. The code presented here was designed to meet four requirements: 1. Python bindings for C++ code (using [`pybind11`](http://pybind11.readthedocs.io/en/stable/index.html) and built with [CMake](http://cmake.org)) @@ -6,7 +7,9 @@ This repository contains an example Python module which wraps C++ code. The code 3. Unit tests for Python code (using `unittest`) 4. A `setuptools` setup.py script for building, installation, and testing -Please see the [blog post that accompanies this repository](http://www.benjack.io/2017/06/12/python-cpp-tests.html) for more information. +Please see the [blog post that accompanies this repository](http://www.benjack.io/2018/02/02/python-cpp-revisited.html) for more information. + +**NOTE**: If you'd like to see the version of the repository that corresponds to my [original June 2017 blog post](http://www.benjack.io/2017/06/12/python-cpp-tests.html), go to [this release](https://github.com/benjaminjack/python_cpp_example/tree/v0.1). However, I no longer recommend using the repository structure from this old release. # Installation diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index b4ff8ab..54753b8 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +#! /usr/bin/env python3 + import os import re import sys @@ -6,9 +8,10 @@ import subprocess from distutils.version import LooseVersion -from setuptools import setup, Extension +from setuptools import setup, Extension, find_packages from setuptools.command.build_ext import build_ext from setuptools.command.test import test as TestCommand +from shutil import copyfile, copymode class CMakeExtension(Extension): @@ -65,39 +68,41 @@ def build_extension(self, ext): cwd=self.build_temp, env=env) subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) + # Copy *_test file to tests directory + test_bin = os.path.join(self.build_temp, 'python_cpp_example_test') + self.copy_test_file(test_bin) print() # Add an empty line for cleaner output -class CatchTestCommand(TestCommand): - """ - A custom test runner to execute both python unittest tests and C++ Catch- - lib tests. - """ - def distutils_dir_name(self, dname): - """Returns the name of a distutils build directory""" - dir_name = "{dirname}.{platform}-{version[0]}.{version[1]}" - return dir_name.format(dirname=dname, - platform=sysconfig.get_platform(), - version=sys.version_info) - - def run(self): - # Run python tests - super(CatchTestCommand, self).run() - print("\nPython tests complete, now running C++ tests...\n") - # Run catch tests - subprocess.call(['./*_test'], - cwd=os.path.join('build', - self.distutils_dir_name('temp')), - shell=True) + def copy_test_file(self, src_file): + ''' + Copy ``src_file`` to ``dest_file`` ensuring parent directory exists. + By default, message like `creating directory /path/to/package` and + `copying directory /src/path/to/package -> path/to/package` are displayed on standard output. Adapted from scikit-build. + ''' + # Create directory if needed + dest_dir = os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'tests', 'bin') + if dest_dir != "" and not os.path.exists(dest_dir): + print("creating directory {}".format(dest_dir)) + os.makedirs(dest_dir) + # Copy file + dest_file = os.path.join(dest_dir, os.path.basename(src_file)) + print("copying {} -> {}".format(src_file, dest_file)) + copyfile(src_file, dest_file) + copymode(src_file, dest_file) setup( name='python_cpp_example', - version='0.1', + version='0.2', author='Benjamin Jack', author_email='benjamin.r.jack@gmail.com', description='A hybrid Python/C++ test project', long_description='', - ext_modules=[CMakeExtension('python_cpp_example')], - cmdclass=dict(build_ext=CMakeBuild, test=CatchTestCommand), + packages=find_packages('src'), + package_dir={'':'src'}, + ext_modules=[CMakeExtension('python_cpp_example/python_cpp_example')], + cmdclass=dict(build_ext=CMakeBuild), + test_suite='tests', zip_safe=False, ) diff --git a/src/python_cpp_example/__init__.py b/src/python_cpp_example/__init__.py new file mode 100644 index 0000000..c221367 --- /dev/null +++ b/src/python_cpp_example/__init__.py @@ -0,0 +1 @@ +from .python_cpp_example import * diff --git a/python_cpp_example/bindings.cpp b/src/python_cpp_example/bindings.cpp similarity index 74% rename from python_cpp_example/bindings.cpp rename to src/python_cpp_example/bindings.cpp index c08188f..d76eb89 100644 --- a/python_cpp_example/bindings.cpp +++ b/src/python_cpp_example/bindings.cpp @@ -3,9 +3,8 @@ namespace py = pybind11; -PYBIND11_PLUGIN(python_cpp_example) -{ - py::module m("python_cpp_example", R"doc( +PYBIND11_PLUGIN(python_cpp_example) { + py::module m("python_cpp_example", R"doc( Python module ----------------------- .. currentmodule:: python_cpp_example @@ -16,17 +15,17 @@ PYBIND11_PLUGIN(python_cpp_example) subtract )doc"); - m.def("add", &add, R"doc( + m.def("add", &add, R"doc( Add two numbers Some other information about the add function. )doc"); - m.def("subtract", &subtract, R"doc( + m.def("subtract", &subtract, R"doc( Subtract two numbers Some other information about the subtract function. )doc"); - return m.ptr(); + return m.ptr(); } \ No newline at end of file diff --git a/src/python_cpp_example/hello.py b/src/python_cpp_example/hello.py new file mode 100644 index 0000000..caf5928 --- /dev/null +++ b/src/python_cpp_example/hello.py @@ -0,0 +1,3 @@ + +def say_hello(): + print("Hello world!") \ No newline at end of file diff --git a/python_cpp_example/math.cpp b/src/python_cpp_example/math.cpp similarity index 100% rename from python_cpp_example/math.cpp rename to src/python_cpp_example/math.cpp diff --git a/python_cpp_example/math.hpp b/src/python_cpp_example/math.hpp similarity index 100% rename from python_cpp_example/math.hpp rename to src/python_cpp_example/math.hpp diff --git a/tests/cpp_test.py b/tests/cpp_test.py new file mode 100644 index 0000000..ff1eaeb --- /dev/null +++ b/tests/cpp_test.py @@ -0,0 +1,15 @@ +import unittest +import subprocess +import os + + +class MainTest(unittest.TestCase): + def test_cpp(self): + print("\n\nTesting C++ code...") + subprocess.check_call(os.path.join(os.path.dirname( + os.path.relpath(__file__)), 'bin', 'python_cpp_example_test')) + print("\nResuming Python tests...\n") + + +if __name__ == '__main__': + unittest.main()
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: