Skip to content

Commit

Permalink
Fix location of package prefixes
Browse files Browse the repository at this point in the history
The current implementation had logic errors -- it did not support paths containing a
'.'.

Support the "root package" and duplicate the logic from distutils, which is
documented and expected.

  https://docs.python.org/2/distutils/setupscript.html#listing-whole-packages
  • Loading branch information
thewtex committed Aug 11, 2016
1 parent 6eaf913 commit 7ed209c
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 15 deletions.
23 changes: 23 additions & 0 deletions skbuild/command/egg_info.py
Expand Up @@ -2,6 +2,7 @@
import os

from setuptools.command.egg_info import egg_info as _egg_info
from setuptools.command.egg_info import manifest_maker as _manifest_maker


class egg_info(_egg_info):
Expand All @@ -12,3 +13,25 @@ def finalize_options(self):
self.egg_base = os.path.join(script_dir, self.egg_base)

_egg_info.finalize_options(self)

def find_sources(self):
"""Generate SOURCES.txt manifest file"""
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
mm = manifest_maker(self.distribution)
mm.manifest = manifest_filename
mm.run()
self.filelist = mm.filelist

class manifest_maker(_manifest_maker):

def add_defaults(self):
import ptpdb; ptpdb.set_trace()
_manifest_maker.add_defaults(self)
old_include_package_data = self.distribution.include_package_data
# self.distribution.include_package_data = True
build_py = self.get_finalized_command('build_py')
df = build_py.data_files
for _, src_dir, _, filenames in build_py.data_files:
self.filelist.extend([os.path.join(src_dir, filename)
for filename in filenames])
self.distribution.include_package_data = old_include_package_data
75 changes: 60 additions & 15 deletions skbuild/setuptools_wrap.py
Expand Up @@ -11,10 +11,7 @@
from .command import build, install, clean, bdist, bdist_wheel, egg_info
from .exceptions import SKBuildError

try:
from setuptools import setup as upstream_setup
except ImportError:
from distutils.core import setup as upstream_setup
from setuptools import setup as upstream_setup


def create_skbuild_argparser():
Expand Down Expand Up @@ -153,33 +150,78 @@ def setup(*args, **kw):
# the data files on the bottom would have been mapped to
# "top.not_a_subpackage" instead of "top", proper -- had such a package been
# specified.
package_prefixes = list(sorted(
(
(package_dir[package].replace('.', '/'), package)
for package in packages
),
key=lambda tup: len(tup[0]),
reverse=True
))
def get_package_prefix(package, package_dir):
"""Return the directory, relative to the top of the source
distribution, where package 'package' should be found
(at least according to the 'package_dir' option, if any).
Modified from Python 2.7.12/3.5.2
distutils.command.build_py:get_package_dir"""

path = package.split('.')

if not package_dir:
if path:
return os.path.join(*path)
else:
return ''
else:
tail = []
while path:
try:
pdir = package_dir['.'.join(path)]
except KeyError:
tail.insert(0, path[-1])
del path[-1]
else:
tail.insert(0, pdir)
return os.path.join(*tail)
else:
# Oops, got all the way through 'path' without finding a
# match in package_dir. If package_dir defines a directory
# for the root (nameless) package, then fallback on it;
# otherwise, we might as well have not consulted
# package_dir at all, as we just use the directory implied
# by 'tail' (which should be the same as the original value
# of 'path' at this point).
pdir = package_dir.get('')
if pdir is not None:
tail.insert(0, pdir)

if tail:
return os.path.join(*tail)
else:
return ''

package_prefixes = []
for package in packages:
prefix = (get_package_prefix(package, package_dir), package)
package_prefixes.append(prefix)
# Add the root (nameless) package
prefix = (get_package_prefix('', package_dir), '')
package_prefixes.append(prefix)
package_prefixes = sorted(package_prefixes,
key=lambda tup: len(tup[0]),
reverse=True)

try:
cmkr = cmaker.CMaker()
cmkr.configure(cmake_args)
cmkr.make(make_args)
except SKBuildError as e:
except SKBuildError as error:
import traceback
print("Traceback (most recent call last):")
traceback.print_tb(sys.exc_info()[2])
print()
sys.exit(e)
sys.exit(error)

_classify_files(cmkr.install(), package_data, package_prefixes, py_modules,
scripts, new_scripts, data_files)

kw['package_data'] = package_data
kw['package_dir'] = {
package: os.path.join(cmaker.CMAKE_INSTALL_DIR, prefix)
for prefix, package in package_prefixes
for package, prefix in package_dir.items()
}

kw['py_modules'] = py_modules
Expand All @@ -194,6 +236,8 @@ def setup(*args, **kw):
for parent_dir, file_set in data_files.items()
]

# kw['include_package_data'] = True

# work around https://bugs.python.org/issue1011113
# (patches provided, but no updates since 2014)
cmdclass = kw.get('cmdclass', {})
Expand All @@ -203,6 +247,7 @@ def setup(*args, **kw):
cmdclass['bdist'] = cmdclass.get('bdist', bdist.bdist)
cmdclass['bdist_wheel'] = cmdclass.get(
'bdist_wheel', bdist_wheel.bdist_wheel)
#import ptpdb; ptpdb.set_trace()
cmdclass['egg_info'] = cmdclass.get('egg_info', egg_info.egg_info)
kw['cmdclass'] = cmdclass

Expand Down
16 changes: 16 additions & 0 deletions tests/test_root_package.py
@@ -0,0 +1,16 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""test_root_package
----------------------------------
Ensure that skbuild supports the root package, i.e. the nameless top level
"package".
"""

from . import project_setup_py_test


@project_setup_py_test(("unit", "root-package"), ["build"], clear_cache=True)
def test_hello_builds():
pass
11 changes: 11 additions & 0 deletions tests/unit/root-package/CMakeLists.txt
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.5.0)

project(root-package)

enable_testing()

find_package(PythonInterp REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(PythonExtensions REQUIRED)

add_subdirectory(lib)
9 changes: 9 additions & 0 deletions tests/unit/root-package/lib/CMakeLists.txt
@@ -0,0 +1,9 @@
add_library(_spam MODULE _spam.c)
python_extension_module(_spam)

add_test(NAME spam
COMMAND ${PYTHON_EXECUTABLE} -m spam
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX})

install(TARGETS _spam LIBRARY DESTINATION "lib")
install(FILES spam.py DESTINATION "lib")
41 changes: 41 additions & 0 deletions tests/unit/root-package/lib/_spam.c
@@ -0,0 +1,41 @@
#include <Python.h>

static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;

if (!PyArg_ParseTuple(args, "s", &command))
return NULL;
sts = system(command);
return PyLong_FromLong(sts);
}


static PyMethodDef spam_methods[] = {
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
{NULL, NULL, 0, NULL} /* Sentinel */
};


#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC init_spam(void)
{
(void) Py_InitModule("_spam", spam_methods);
}
#else /* PY_MAJOR_VERSION >= 3 */
static struct PyModuleDef spam_module_def = {
PyModuleDef_HEAD_INIT,
"_spam",
"Internal \"_spam\" module",
-1,
spam_methods
};

PyMODINIT_FUNC PyInit__spam(void)
{
return PyModule_Create(&spam_module_def);
}
#endif /* PY_MAJOR_VERSION >= 3 */
1 change: 1 addition & 0 deletions tests/unit/root-package/lib/spam.py
@@ -0,0 +1 @@
from ._spam import spam # noqa: F401
11 changes: 11 additions & 0 deletions tests/unit/root-package/setup.py
@@ -0,0 +1,11 @@
from skbuild import setup

setup(
name="root-package",
version="1.2.3",
description="a package that populates the root (nameless) package",
author='The scikit-build team',
license="MIT",
package_dir={'': 'lib'},
py_modules=['spam']
)

0 comments on commit 7ed209c

Please sign in to comment.