Repository: spack/spack

Issue:
pybind11: fix get_include()
The `py-pybind11` package has a python module helper of the form:

```python
import pybind11 as py
print(py.get_include())
```

which helps downstream, if they are not using the CMake config package (which probably everyone is using), to query the install location.

`get_include()` currently points to the spec's Python include location instead of the package's include.

Diff for a new unit test:
```diff
diff --git a/var/spack/repos/builtin/packages/py-pybind11/package.py b/var/spack/repos/builtin/packages/py-pybind11/package.py
index cd482ceb3..0a86afb97 100644
--- a/var/spack/repos/builtin/packages/py-pybind11/package.py
+++ b/var/spack/repos/builtin/packages/py-pybind11/package.py
@@ -60,3 +60,17 @@ class PyPybind11(CMakePackage):
         super(PyPybind11, self).install(spec, prefix)
         setup_py('install', '--single-version-externally-managed', '--root=/',
                  '--prefix={0}'.format(prefix))
+
+    @run_after('install')
+    @on_package_attributes(run_tests=True)
+    def test(self):
+        with working_dir('spack-test', create=True):
+            # test include helper points to right location
+            module = "pybind11"
+            python = Executable(self.spec['python'].command.path)
+            python('-c', 'import {0}'.format(module))
+            inc = python('-c', 'import {0} as py; print(py.get_include())'.format(
+                module), output=str)
+            print("INC:")
+            print(inc)
+            assert inc == self.prefix.include
```

Similar to:
- https://github.com/conda-forge/pybind11-feedstock/pull/32
- https://github.com/pybind/pybind11/pull/1877


Discussion:
@adamjstewart do you think I could just patch-in on install a hard coded [installed path](https://github.com/pybind/pybind11/blob/v2.4.3/pybind11/__init__.py#L17-L18) to our `self.prefix.include` into that module?
Yeah, that's probably the easiest way. `sys.prefix` will always be wrong, unless you activate the package.
Ok, sorry for the follow-up: do we have a mechanism to apply such a "non-static" patch? Probably via `filter`?
Depends on when and where you want to do it. For example, to do it after installation, use:
```python
@run_after('install')
def fix_get_include(self):
    filter_file('before', 'after', 'filename.py')
```
The tricky part is that the line you are trying to replace is 2 lines instead of 1. Maybe filter one of the lines above? I assume we will never care about the virtualenv/conda scenarios since everything is Spack-installed.
Ah dang, that file gets byte compiled ;) Ok, pre-install then I guess :D

Resolving patch:
diff --git a/var/spack/repos/builtin/packages/py-pybind11/package.py b/var/spack/repos/builtin/packages/py-pybind11/package.py
--- a/var/spack/repos/builtin/packages/py-pybind11/package.py
+++ b/var/spack/repos/builtin/packages/py-pybind11/package.py
@@ -56,7 +56,27 @@ def cmake_args(self):
     def setup_build_environment(self, env):
         env.set('PYBIND11_USE_CMAKE', 1)
 
+    def patch(self):
+        """ see https://github.com/spack/spack/issues/13559 """
+        filter_file('import sys',
+                    'import sys; return "{0}"'.format(self.prefix.include),
+                    'pybind11/__init__.py',
+                    string=True)
+
     def install(self, spec, prefix):
         super(PyPybind11, self).install(spec, prefix)
         setup_py('install', '--single-version-externally-managed', '--root=/',
                  '--prefix={0}'.format(prefix))
+
+    @run_after('install')
+    @on_package_attributes(run_tests=True)
+    def test(self):
+        with working_dir('spack-test', create=True):
+            # test include helper points to right location
+            python = self.spec['python'].command
+            inc = python(
+                '-c',
+                'import pybind11 as py; ' +
+                self.spec['python'].package.print_string('py.get_include()'),
+                output=str)
+            assert inc.strip() == str(self.prefix.include)


Test patch: