Exemplo n.º 1
0
    def test_get_outputs(self):
        project_dir, dist = self.create_dist()
        os.chdir(project_dir)
        os.mkdir('spam')
        cmd = install_lib(dist)

        # setting up a dist environment
        cmd.compile = True
        cmd.optimize = 1
        cmd.install_dir = self.mkdtemp()
        f = os.path.join(project_dir, 'spam', '__init__.py')
        self.write_file(f, '# python package')
        cmd.distribution.ext_modules = [Extension('foo', ['xxx'])]
        cmd.distribution.packages = ['spam']

        # make sure the build_lib is set the temp dir  # XXX what?  this is not
        # needed in the same distutils test and should work without manual
        # intervention
        build_dir = os.path.split(project_dir)[0]
        cmd.get_finalized_command('build_py').build_lib = build_dir

        # get_outputs should return 4 elements: spam/__init__.py, .pyc and
        # .pyo, foo*.so / foo.pyd
        outputs = cmd.get_outputs()
        self.assertEqual(len(outputs), 4, outputs)
    def test_build_ext(self):
        support.copy_xxmodule_c(self.tmp_dir)
        xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
        xx_ext = Extension('xx', [xx_c])
        dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
        dist.package_dir = self.tmp_dir
        cmd = build_ext(dist)
        support.fixup_build_ext(cmd)
        cmd.build_lib = self.tmp_dir
        cmd.build_temp = self.tmp_dir
        cmd.ensure_finalized()
        cmd.run()

        code = textwrap.dedent("""\
            import sys
            sys.path.insert(0, %r)

            import xx

            for attr in ('error', 'foo', 'new', 'roj'):
                assert hasattr(xx, attr)

            assert xx.foo(2, 5) == 7
            assert xx.foo(13, 15) == 28
            assert xx.new().demo() is None
            doc = 'This is a template module just for instruction.'
            assert xx.__doc__ == doc
            assert isinstance(xx.Null(), xx.Null)
            assert isinstance(xx.Str(), xx.Str)
            """)
        code = code % self.tmp_dir
        assert_python_ok('-c', code)
    def test_optional_extension(self):

        # this extension will fail, but let's ignore this failure
        # with the optional argument.
        modules = [Extension('foo', ['xxx'], optional=False)]
        dist = Distribution({'name': 'xx', 'ext_modules': modules})
        cmd = build_ext(dist)
        cmd.ensure_finalized()
        self.assertRaises((UnknownFileError, CompileError),
                          cmd.run)  # should raise an error

        modules = [Extension('foo', ['xxx'], optional=True)]
        dist = Distribution({'name': 'xx', 'ext_modules': modules})
        cmd = build_ext(dist)
        cmd.ensure_finalized()
        cmd.run()  # should pass
Exemplo n.º 4
0
    def test_old_record_extensions(self):
        # test pre-PEP 376 --record option with ext modules
        install_dir = self.mkdtemp()
        project_dir, dist = self.create_dist(
            ext_modules=[Extension('xx', ['xxmodule.c'])])
        os.chdir(project_dir)
        support.copy_xxmodule_c(project_dir)

        buildextcmd = build_ext(dist)
        support.fixup_build_ext(buildextcmd)
        buildextcmd.ensure_finalized()

        cmd = install_dist(dist)
        dist.command_obj['install_dist'] = cmd
        dist.command_obj['build_ext'] = buildextcmd
        cmd.root = install_dir
        cmd.record = os.path.join(project_dir, 'filelist')
        cmd.ensure_finalized()
        cmd.run()

        with open(cmd.record) as f:
            content = f.read()

        found = [os.path.basename(line) for line in content.splitlines()]
        expected = [
            _make_ext_name('xx'), 'METADATA', 'INSTALLER', 'REQUESTED',
            'RECORD'
        ]
        self.assertEqual(found, expected)
    def _try_compile_deployment_target(self, operator, target):
        orig_environ = os.environ
        os.environ = orig_environ.copy()
        self.addCleanup(setattr, os, 'environ', orig_environ)

        if target is None:
            if os.environ.get('MACOSX_DEPLOYMENT_TARGET'):
                del os.environ['MACOSX_DEPLOYMENT_TARGET']
        else:
            os.environ['MACOSX_DEPLOYMENT_TARGET'] = target

        deptarget_c = os.path.join(self.tmp_dir, 'deptargetmodule.c')

        with open(deptarget_c, 'w') as fp:
            fp.write(textwrap.dedent('''\
                #include <AvailabilityMacros.h>

                int dummy;

                #if TARGET %s MAC_OS_X_VERSION_MIN_REQUIRED
                #else
                #error "Unexpected target"
                #endif

            ''' % operator))

        # get the deployment target that the interpreter was built with
        target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
        target = tuple(map(int, target.split('.')))
        target = '%02d%01d0' % target

        deptarget_ext = Extension(
            'deptarget',
            [deptarget_c],
            extra_compile_args=['-DTARGET=%s' % (target,)],
        )
        dist = Distribution({
            'name': 'deptarget',
            'ext_modules': [deptarget_ext],
        })
        dist.package_dir = self.tmp_dir
        cmd = build_ext(dist)
        cmd.build_lib = self.tmp_dir
        cmd.build_temp = self.tmp_dir

        try:
            cmd.ensure_finalized()
            cmd.run()
        except CompileError:
            self.fail("Wrong deployment target during compilation")
Exemplo n.º 6
0
    def test_get_inputs(self):
        project_dir, dist = self.create_dist()
        os.chdir(project_dir)
        os.mkdir('spam')
        cmd = install_lib(dist)

        # setting up a dist environment
        cmd.compile = True
        cmd.optimize = 1
        cmd.install_dir = self.mkdtemp()
        f = os.path.join(project_dir, 'spam', '__init__.py')
        self.write_file(f, '# python package')
        cmd.distribution.ext_modules = [Extension('foo', ['xxx'])]
        cmd.distribution.packages = ['spam']

        # get_inputs should return 2 elements: spam/__init__.py and
        # foo*.so / foo.pyd
        inputs = cmd.get_inputs()
        self.assertEqual(len(inputs), 2, inputs)
    def test_record_basic(self):
        install_dir = self.mkdtemp()
        modules_dest = os.path.join(install_dir, 'lib')
        scripts_dest = os.path.join(install_dir, 'bin')
        project_dir, dist = self.create_dist(
            name='Spamlib',
            version='0.1',
            py_modules=['spam'],
            scripts=['spamd'],
            ext_modules=[Extension('_speedspam', ['_speedspam.c'])])

        # using a real install_dist command is too painful, so we use a mock
        # class that's only a holder for options to be used by install_distinfo
        # and we create placeholder files manually instead of using build_*.
        # the install_* commands will still be consulted by install_distinfo.
        os.chdir(project_dir)
        self.write_file('spam', '# Python module')
        self.write_file('spamd', '# Python script')
        extmod = '_speedspam' + sysconfig.get_config_var('SO')
        self.write_file(extmod, '')

        install = DummyInstallCmd(dist)
        install.outputs = ['spam', 'spamd', extmod]
        install.install_lib = modules_dest
        install.install_scripts = scripts_dest
        dist.command_obj['install_dist'] = install

        cmd = install_distinfo(dist)
        cmd.ensure_finalized()
        dist.command_obj['install_distinfo'] = cmd
        cmd.run()

        # checksum and size are not hard-coded for METADATA as it is
        # platform-dependent (line endings)
        metadata = os.path.join(modules_dest, 'Spamlib-0.1.dist-info',
                                'METADATA')
        with open(metadata, 'rb') as fp:
            content = fp.read()

        metadata_size = str(len(content))
        metadata_md5 = hashlib.md5(content).hexdigest()

        record = os.path.join(modules_dest, 'Spamlib-0.1.dist-info', 'RECORD')
        with open(record, encoding='utf-8') as fp:
            content = fp.read()

        found = []
        for line in content.splitlines():
            filename, checksum, size = line.split(',')
            filename = os.path.basename(filename)
            found.append((filename, checksum, size))

        expected = [
            ('spam', '6ab2f288ef2545868effe68757448b45', '15'),
            ('spamd', 'd13e6156ce78919a981e424b2fdcd974', '15'),
            (extmod, 'd41d8cd98f00b204e9800998ecf8427e', '0'),
            ('METADATA', metadata_md5, metadata_size),
            ('INSTALLER', '44e3fde05f3f537ed85831969acf396d', '9'),
            ('REQUESTED', 'd41d8cd98f00b204e9800998ecf8427e', '0'),
            ('RECORD', '', ''),
        ]
        self.assertEqual(found, expected)
Exemplo n.º 8
0
    def _read_setup_cfg(self, parser, cfg_filename):
        cfg_directory = os.path.dirname(os.path.abspath(cfg_filename))
        content = {}
        for section in parser.sections():
            content[section] = dict(parser.items(section))

        # global setup hooks are called first
        if 'global' in content:
            if 'setup_hooks' in content['global']:
                setup_hooks = split_multiline(content['global']['setup_hooks'])

                # add project directory to sys.path, to allow hooks to be
                # distributed with the project
                sys.path.insert(0, cfg_directory)
                try:
                    for line in setup_hooks:
                        try:
                            hook = resolve_name(line)
                        except ImportError as e:
                            logger.warning('cannot find setup hook: %s',
                                           e.args[0])
                        else:
                            self.setup_hooks.append(hook)
                    self.run_hooks(content)
                finally:
                    sys.path.pop(0)

        metadata = self.dist.metadata

        # setting the metadata values
        if 'metadata' in content:
            for key, value in content['metadata'].items():
                key = key.replace('_', '-')
                if metadata.is_multi_field(key):
                    value = split_multiline(value)

                if key == 'project-url':
                    value = [(label.strip(), url.strip())
                             for label, url in
                             [v.split(',') for v in value]]

                if key == 'description-file':
                    if 'description' in content['metadata']:
                        msg = ("description and description-file' are "
                               "mutually exclusive")
                        raise PackagingOptionError(msg)

                    filenames = value.split()

                    # concatenate all files
                    value = []
                    for filename in filenames:
                        # will raise if file not found
                        with open(filename) as description_file:
                            value.append(description_file.read().strip())
                        # add filename as a required file
                        if filename not in metadata.requires_files:
                            metadata.requires_files.append(filename)
                    value = '\n'.join(value).strip()
                    key = 'description'

                if metadata.is_metadata_field(key):
                    metadata[key] = self._convert_metadata(key, value)

        if 'files' in content:
            files = content['files']
            self.dist.package_dir = files.pop('packages_root', None)

            files = dict((key, split_multiline(value)) for key, value in
                         files.items())

            self.dist.packages = []

            packages = files.get('packages', [])
            if isinstance(packages, str):
                packages = [packages]

            for package in packages:
                if ':' in package:
                    dir_, package = package.split(':')
                    self.dist.package_dir[package] = dir_
                self.dist.packages.append(package)

            self.dist.py_modules = files.get('modules', [])
            if isinstance(self.dist.py_modules, str):
                self.dist.py_modules = [self.dist.py_modules]
            self.dist.scripts = files.get('scripts', [])
            if isinstance(self.dist.scripts, str):
                self.dist.scripts = [self.dist.scripts]

            self.dist.package_data = {}
            # bookkeeping for the loop below
            firstline = True
            prev = None

            for line in files.get('package_data', []):
                if '=' in line:
                    # package name -- file globs or specs
                    key, value = line.split('=')
                    prev = self.dist.package_data[key.strip()] = value.split()
                elif firstline:
                    # invalid continuation on the first line
                    raise PackagingOptionError(
                        'malformed package_data first line: %r (misses "=")' %
                        line)
                else:
                    # continuation, add to last seen package name
                    prev.extend(line.split())

                firstline = False

            self.dist.data_files = []
            for data in files.get('data_files', []):
                data = data.split('=')
                if len(data) != 2:
                    continue
                key, value = data
                values = [v.strip() for v in value.split(',')]
                self.dist.data_files.append((key, values))

            # manifest template
            self.dist.extra_files = files.get('extra_files', [])

            resources = []
            for rule in files.get('resources', []):
                glob, destination = rule.split('=', 1)
                rich_glob = glob.strip().split(' ', 1)
                if len(rich_glob) == 2:
                    prefix, suffix = rich_glob
                else:
                    assert len(rich_glob) == 1
                    prefix = ''
                    suffix = glob
                if destination == '<exclude>':
                    destination = None
                resources.append(
                    (prefix.strip(), suffix.strip(), destination.strip()))
                self.dist.data_files = get_resources_dests(
                    cfg_directory, resources)

        ext_modules = self.dist.ext_modules
        for section_key in content:
            # no str.partition in 2.4 :(
            labels = section_key.split(':')
            if len(labels) == 2 and labels[0] == 'extension':
                values_dct = content[section_key]
                if 'name' in values_dct:
                    raise PackagingOptionError(
                        'extension name should be given as [extension: name], '
                        'not as key')
                name = labels[1].strip()
                _check_name(name, self.dist.packages)
                ext_modules.append(Extension(
                    name,
                    _pop_values(values_dct, 'sources'),
                    _pop_values(values_dct, 'include_dirs'),
                    _pop_values(values_dct, 'define_macros'),
                    _pop_values(values_dct, 'undef_macros'),
                    _pop_values(values_dct, 'library_dirs'),
                    _pop_values(values_dct, 'libraries'),
                    _pop_values(values_dct, 'runtime_library_dirs'),
                    _pop_values(values_dct, 'extra_objects'),
                    _pop_values(values_dct, 'extra_compile_args'),
                    _pop_values(values_dct, 'extra_link_args'),
                    _pop_values(values_dct, 'export_symbols'),
                    _pop_values(values_dct, 'swig_opts'),
                    _pop_values(values_dct, 'depends'),
                    values_dct.pop('language', None),
                    values_dct.pop('optional', None),
                    **values_dct))
    def test_get_outputs(self):
        tmp_dir = self.mkdtemp()
        c_file = os.path.join(tmp_dir, 'foo.c')
        self.write_file(c_file, 'void PyInit_foo(void) {}\n')
        ext = Extension('foo', [c_file], optional=False)
        dist = Distribution({'name': 'xx',
                             'ext_modules': [ext]})
        cmd = build_ext(dist)
        support.fixup_build_ext(cmd)
        cmd.ensure_finalized()
        self.assertEqual(len(cmd.get_outputs()), 1)

        cmd.build_lib = os.path.join(self.tmp_dir, 'build')
        cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')

        # issue #5977 : distutils build_ext.get_outputs
        # returns wrong result with --inplace
        other_tmp_dir = os.path.realpath(self.mkdtemp())
        old_wd = os.getcwd()
        os.chdir(other_tmp_dir)
        try:
            cmd.inplace = True
            cmd.run()
            so_file = cmd.get_outputs()[0]
        finally:
            os.chdir(old_wd)
        self.assertTrue(os.path.exists(so_file))
        so_ext = sysconfig.get_config_var('SO')
        self.assertTrue(so_file.endswith(so_ext))
        so_dir = os.path.dirname(so_file)
        self.assertEqual(so_dir, other_tmp_dir)

        cmd.inplace = False
        cmd.run()
        so_file = cmd.get_outputs()[0]
        self.assertTrue(os.path.exists(so_file))
        self.assertTrue(so_file.endswith(so_ext))
        so_dir = os.path.dirname(so_file)
        self.assertEqual(so_dir, cmd.build_lib)

        # inplace = False, cmd.package = 'bar'
        build_py = cmd.get_finalized_command('build_py')
        build_py.package_dir = 'bar'
        path = cmd.get_ext_fullpath('foo')
        # checking that the last directory is the build_dir
        path = os.path.split(path)[0]
        self.assertEqual(path, cmd.build_lib)

        # inplace = True, cmd.package = 'bar'
        cmd.inplace = True
        other_tmp_dir = os.path.realpath(self.mkdtemp())
        old_wd = os.getcwd()
        os.chdir(other_tmp_dir)
        try:
            path = cmd.get_ext_fullpath('foo')
        finally:
            os.chdir(old_wd)
        # checking that the last directory is bar
        path = os.path.split(path)[0]
        lastdir = os.path.split(path)[-1]
        self.assertEqual(lastdir, 'bar')
 def test_get_source_files(self):
     modules = [Extension('foo', ['xxx'], optional=False)]
     dist = Distribution({'name': 'xx', 'ext_modules': modules})
     cmd = build_ext(dist)
     cmd.ensure_finalized()
     self.assertEqual(cmd.get_source_files(), ['xxx'])
    def test_finalize_options(self):
        # Make sure Python's include directories (for Python.h, pyconfig.h,
        # etc.) are in the include search path.
        modules = [Extension('foo', ['xxx'], optional=False)]
        dist = Distribution({'name': 'xx', 'ext_modules': modules})
        cmd = build_ext(dist)
        cmd.finalize_options()

        py_include = sysconfig.get_path('include')
        self.assertIn(py_include, cmd.include_dirs)

        plat_py_include = sysconfig.get_path('platinclude')
        self.assertIn(plat_py_include, cmd.include_dirs)

        # make sure cmd.libraries is turned into a list
        # if it's a string
        cmd = build_ext(dist)
        cmd.libraries = 'my_lib, other_lib lastlib'
        cmd.finalize_options()
        self.assertEqual(cmd.libraries, ['my_lib', 'other_lib', 'lastlib'])

        # make sure cmd.library_dirs is turned into a list
        # if it's a string
        cmd = build_ext(dist)
        cmd.library_dirs = 'my_lib_dir%sother_lib_dir' % os.pathsep
        cmd.finalize_options()
        self.assertIn('my_lib_dir', cmd.library_dirs)
        self.assertIn('other_lib_dir', cmd.library_dirs)

        # make sure rpath is turned into a list
        # if it's a string
        cmd = build_ext(dist)
        cmd.rpath = 'one%stwo' % os.pathsep
        cmd.finalize_options()
        self.assertEqual(cmd.rpath, ['one', 'two'])

        # XXX more tests to perform for win32

        # make sure define is turned into 2-tuples
        # strings if they are ','-separated strings
        cmd = build_ext(dist)
        cmd.define = 'one,two'
        cmd.finalize_options()
        self.assertEqual(cmd.define, [('one', '1'), ('two', '1')])

        # make sure undef is turned into a list of
        # strings if they are ','-separated strings
        cmd = build_ext(dist)
        cmd.undef = 'one,two'
        cmd.finalize_options()
        self.assertEqual(cmd.undef, ['one', 'two'])

        # make sure swig_opts is turned into a list
        cmd = build_ext(dist)
        cmd.swig_opts = None
        cmd.finalize_options()
        self.assertEqual(cmd.swig_opts, [])

        cmd = build_ext(dist)
        cmd.swig_opts = '1 2'
        cmd.finalize_options()
        self.assertEqual(cmd.swig_opts, ['1', '2'])