Exemple #1
0
async def test_include_ros_base():
    pkg = PackageDescriptor('package/path')
    pkg.name = 'MyPackageName'
    pkg.dependencies['run'] = {}
    installers = {
        'apt': MagicMock(),
    }
    top_level_args = MagicMock(build_base='build/base',
                               install_base='install/base',
                               bundle_base='bundle/base')
    args = BundlePackageArguments(pkg, installers, top_level_args)
    args.ros_distribution = 'kinetic'
    args.exclude_ros_base = False

    context = TaskContext(pkg=pkg, args=args, dependencies={})
    task = RosBundle()
    task.set_context(context=context)

    # Concise read on why it's patched this way.
    # http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch
    with patch('colcon_ros_bundle.task.ros_bundle.RosdepWrapper'
               ) as wrapper:  # noqa: E501
        with patch('os.environ') as environ:
            environ.__getitem__.side_effect = access_var
            wrapper().get_rule.side_effect = _get_rule_side_effect
            wrapper().resolve.side_effect = _resolve_side_effect
            await task.bundle()

    installers['apt'].add_to_install_list.assert_called_with(
        'ros-kinetic-ros-base')
Exemple #2
0
def test_identify():
    extension = PythonPackageIdentification()

    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        desc = PackageDescriptor(basepath)
        desc.type = 'other'
        assert extension.identify(desc) is None
        assert desc.name is None

        desc.type = None
        assert extension.identify(desc) is None
        assert desc.name is None
        assert desc.type is None

        basepath = Path(basepath)
        (basepath / 'setup.py').write_text('')
        assert extension.identify(desc) is None
        assert desc.name is None
        assert desc.type is None

        (basepath / 'setup.cfg').write_text('')
        assert extension.identify(desc) is None
        assert desc.name is None
        assert desc.type is None

        (basepath / 'setup.cfg').write_text('[metadata]\n' 'name = pkg-name\n')
        assert extension.identify(desc) is None
        assert desc.name == 'pkg-name'
        assert desc.type == 'python'

        desc.name = 'other-name'
        with pytest.raises(RuntimeError) as e:
            extension.identify(desc)
        assert str(e).endswith('Package name already set to different value')

        (basepath / 'setup.cfg').write_text(
            '[metadata]\n'
            'name = other-name\n'
            '[options]\n'
            'setup_requires =\n'
            "  build; sys_platform != 'win32'\n"
            "  build-windows; sys_platform == 'win32'\n"
            'install_requires =\n'
            '  runA > 1.2.3\n'
            '  runB\n'
            'tests_require = test == 2.0.0\n'
            'zip_safe = false\n')
        assert extension.identify(desc) is None
        assert desc.name == 'other-name'
        assert desc.type == 'python'
        assert set(desc.dependencies.keys()) == {'build', 'run', 'test'}
        assert desc.dependencies['build'] == {'build', 'build-windows'}
        assert desc.dependencies['run'] == {'runA', 'runB'}
        dep = next(x for x in desc.dependencies['run'] if x == 'runA')
        assert dep.metadata['version_gt'] == '1.2.3'
        assert desc.dependencies['test'] == {'test'}

        assert callable(desc.metadata['get_python_setup_options'])
        options = desc.metadata['get_python_setup_options'](None)
        assert 'zip_safe' in options
Exemple #3
0
async def test_rosdistro_not_defined():
    pkg = PackageDescriptor('package/path')
    pkg.name = 'MyPackageName'
    pkg.dependencies['run'] = {}
    installers = {
        'apt': MagicMock(),
    }
    top_level_args = MagicMock(build_base='build/base',
                               install_base='install/base',
                               bundle_base='bundle/base')
    args = BundlePackageArguments(pkg, installers, top_level_args)

    context = TaskContext(pkg=pkg, args=args, dependencies={})
    task = RosBundle()
    task.set_context(context=context)

    # Concise read on why it's patched this way.
    # http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch
    with patch('colcon_ros_bundle.task.ros_bundle.RosdepWrapper') as wrapper:  # noqa: E501
        with pytest.raises(RuntimeError):
            wrapper().get_rule.side_effect = _get_rule_side_effect
            wrapper().resolve.side_effect = _resolve_side_effect
            await task.bundle()

    installers['apt'].add_to_install_list.assert_not_called()
Exemple #4
0
async def test_bundle():
    descriptor = PackageDescriptor('some/path')
    descriptor.name = 'python_package'
    deps = [DependencyDescriptor('pkg1', metadata={'version_eq': '1.3.2'}),
            DependencyDescriptor('pkg_in_workspace'),
            DependencyDescriptor('pkg2', metadata={'version_lt': '1.2'}),
            'ignored_pkg']
    descriptor.dependencies['run'] = deps

    workspace = {'pkg_in_workspace': 'path/to/pkg'}
    task_args = MagicMock(build_base='build/base',
                          install_base='install/base',
                          bundle_base='bundle/base')
    pip_installer = MagicMock()
    apt_installer = MagicMock()
    args = BundlePackageArguments(
        descriptor, {'pip3': pip_installer, 'apt': apt_installer}, task_args)
    context = TaskContext(pkg=descriptor, args=args, dependencies=workspace)
    task = PythonBundleTask()
    task.set_context(context=context)

    await task.bundle()

    pip_installer.add_to_install_list.assert_called_once_with('pkg1==1.3.2')

    apt_calls = apt_installer.add_to_install_list.call_args_list
    assert len(apt_calls) == 2
    assert apt_calls[0][0][0] == 'libpython3-dev'
    assert apt_calls[1][0][0] == 'python3-pip'
Exemple #5
0
def test_no_augmentation():
    augmentation_extension = DirhashPackageAugmentation()

    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        desc = PackageDescriptor(basepath)
        desc.metadata['vcs_type'] = 'default'

        augmentation_extension.augment_package(desc)
        assert desc.metadata['vcs_type'] == 'default'
Exemple #6
0
def test_identifies_package():
    d = PackageDescriptor('/some/path')
    assert not d.identifies_package()
    d.type = 'type'
    assert not d.identifies_package()
    d.type = None
    d.name = 'name'
    assert not d.identifies_package()
    d.type = 'type'
    assert d.identifies_package()
Exemple #7
0
def test_augment_packages():
    desc1 = PackageDescriptor('/some/path')
    desc2 = PackageDescriptor('/other/path')
    descs = {desc1, desc2}
    with EntryPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_package_augmentation_extensions()
        extensions['extension1'].augment_package = Mock(
            side_effect=augment_package_metadata_with_data)
        extensions['extension2'].augment_package = Mock(
            side_effect=augment_package_metadata_with_path)
        augment_packages(descs)
    assert len(desc1.metadata) == 2
    assert set(desc1.metadata.keys()) == {'key', 'path'}
    assert desc1.path == desc1.metadata['path']

    assert len(desc2.metadata) == 1
    assert set(desc2.metadata.keys()) == {'path'}
    assert desc2.path == desc2.metadata['path']

    # raise exception
    desc1 = PackageDescriptor('/some/path')
    desc2 = PackageDescriptor('/other/path')
    descs = {desc1, desc2}
    with EntryPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_package_augmentation_extensions()
    extensions['extension1'].augment_package = Mock(
        side_effect=augment_package_with_hook)
    with patch('colcon_core.package_augmentation.logger.error') as error:
        augment_packages(
            descs, additional_argument_names=['arg1', 'arg2'],
            augmentation_extensions=extensions)
    assert desc1.hooks == ['arg1', 'arg2']
    assert desc2.hooks == ['arg1', 'arg2']
    # the raised exception is catched and results in an error message
    assert error.call_count == 1
    assert len(error.call_args[0]) == 1
    assert error.call_args[0][0].startswith(
        "Exception in package augmentation extension 'extension2': \n")

    # invalid return value
    desc1.hooks = []
    desc2.hooks = []
    extensions['extension2'].augment_packages = Mock(return_value=False)
    with patch('colcon_core.package_augmentation.logger.error') as error:
        augment_packages(
            descs, additional_argument_names=['arg1', 'arg2'],
            augmentation_extensions=extensions)
    assert desc1.hooks == ['arg1', 'arg2']
    assert desc2.hooks == ['arg1', 'arg2']
    # the raised assertion is catched and results in an error message
    assert error.call_count == 1
    assert len(error.call_args[0]) == 1
    assert error.call_args[0][0].startswith(
        "Exception in package augmentation extension 'extension2': ")
 def test_dependencies_not_changed(self):
     package_1_desc = PackageDescriptor('fake/path')
     package_1_desc.name = 'baz'
     package_1_desc.dependencies['run'] = ['foo']
     package_1_desc.dependencies['test'] = ['bar']
     package_1 = PackageDecorator(package_1_desc)
     decorators = [package_1]
     self.assertTrue(
         package_dependencies_changed(self.path_context, decorators))
     update_dependencies_cache(self.path_context)
     self.assertFalse(
         package_dependencies_changed(self.path_context, decorators))
Exemple #9
0
def test_build_package():
    event_loop = new_event_loop()
    asyncio.set_event_loop(event_loop)
    try:
        with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
            tmp_path = Path(tmp_path_str)
            python_build_task = PythonBuildTask()
            package = PackageDescriptor(tmp_path / 'src')
            package.name = 'test_package'
            package.type = 'python'

            context = TaskContext(
                pkg=package,
                args=SimpleNamespace(
                    path=str(tmp_path / 'src'),
                    build_base=str(tmp_path / 'build'),
                    install_base=str(tmp_path / 'install'),
                    symlink_install=False,
                ),
                dependencies={}
            )
            python_build_task.set_context(context=context)

            pkg = python_build_task.context.pkg

            pkg.path.mkdir()
            (pkg.path / 'setup.py').write_text(
                'from setuptools import setup\n'
                'setup(\n'
                '    name="test_package",\n'
                '    packages=["my_module"],\n'
                ')\n'
            )
            (pkg.path / 'my_module').mkdir()
            (pkg.path / 'my_module' / '__init__.py').touch()

            src_base = Path(python_build_task.context.args.path)

            source_files_before = set(src_base.rglob('*'))
            event_loop.run_until_complete(python_build_task.build())
            source_files_after = set(src_base.rglob('*'))
            assert source_files_before == source_files_after

            build_base = Path(python_build_task.context.args.build_base)
            assert 1 == len(list(build_base.rglob('my_module/__init__.py')))

            install_base = Path(python_build_task.context.args.install_base)
            assert 1 == len(list(install_base.rglob('my_module/__init__.py')))

            pkg_info, = install_base.rglob('PKG-INFO')
            assert 'Name: test-package' in pkg_info.read_text().splitlines()
    finally:
        event_loop.close()
Exemple #10
0
def test__discover_packages():
    descs = _discover_packages(None, None, {})
    assert descs == set()

    with EntryPointContext(
            extension1=Extension1,
            extension2=Extension2,
            extension3=Extension3,
            extension4=Extension4,
    ):
        extensions = get_package_discovery_extensions()

        # mock the discover method in the order the extensions are being called
        extensions['extension2'].discover = Mock(
            side_effect=ValueError('exception in discover'))
        extensions['extension4'].discover = Mock(
            side_effect=extensions['extension4'].discover)
        extensions['extension3'].discover = Mock(
            return_value={
                PackageDescriptor('/extension3/pkg1'),
                PackageDescriptor('/extension3/pkg2')
            })
        # returns None instead of a set
        extensions['extension1'].discover = Mock()

        with patch('colcon_core.package_discovery.logger.error') as error:
            descs = _discover_packages(Mock(), None, extensions)

            # in the order the extensions are being called
            assert extensions['extension2'].discover.call_count == 1
            assert extensions['extension4'].discover.call_count == 1
            assert extensions['extension3'].discover.call_count == 1
            assert extensions['extension1'].discover.call_count == 1

            # the raised exceptions are catched and result in error messages
            assert error.call_count == 2
            assert len(error.call_args_list[0][0]) == 1
            assert error.call_args_list[0][0][0].startswith(
                "Exception in package discovery extension 'extension2': "
                'exception in discover\n')
            assert len(error.call_args_list[1][0]) == 1
            assert error.call_args_list[1][0][0].startswith(
                "Exception in package discovery extension 'extension1': "
                'discover() should return a set\n')

        assert len(descs) == 2
        expected_path = '/extension3/pkg1'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)
        expected_path = '/extension3/pkg2'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)
Exemple #11
0
def test_update_metadata():
    desc = PackageDescriptor('/some/path')
    desc.name = 'name'
    assert len(desc.metadata) == 0

    update_metadata(desc, 'd', {1: 'one', 2: 'two'})
    assert len(desc.metadata) == 1
    assert 'd' in desc.metadata.keys()
    assert desc.metadata['d'] == {1: 'one', 2: 'two'}

    update_metadata(desc, 'd', {2: 'TWO', 3: 'THREE'})
    assert len(desc.metadata) == 1
    assert 'd' in desc.metadata.keys()
    assert desc.metadata['d'] == {1: 'one', 2: 'TWO', 3: 'THREE'}

    update_metadata(desc, 'l', [1, 2])
    assert len(desc.metadata) == 2
    assert 'l' in desc.metadata.keys()
    assert desc.metadata['l'] == [1, 2]

    update_metadata(desc, 'l', [2, 3])
    assert len(desc.metadata) == 2
    assert 'l' in desc.metadata.keys()
    assert desc.metadata['l'] == [1, 2, 2, 3]

    update_metadata(desc, 's', {1, 2})
    assert len(desc.metadata) == 3
    assert 's' in desc.metadata.keys()
    assert desc.metadata['s'] == {1, 2}

    update_metadata(desc, 's', {2, 3})
    assert len(desc.metadata) == 3
    assert 's' in desc.metadata.keys()
    assert desc.metadata['s'] == {1, 2, 3}

    with patch('colcon_core.package_augmentation.logger.warn') as warn:
        update_metadata(desc, 's', 'different type')
    warn.assert_called_once_with(
        "update package 'name' metadata 's' from value '{1, 2, 3}' to "
        "'different type'")
    assert len(desc.metadata) == 3
    assert 's' in desc.metadata.keys()
    assert desc.metadata['s'] == 'different type'

    with patch('colcon_core.package_augmentation.logger.warn') as warn:
        update_metadata(desc, 's', 'same type')
    assert warn.call_count == 0
    assert len(desc.metadata) == 3
    assert 's' in desc.metadata.keys()
    assert desc.metadata['s'] == 'same type'
Exemple #12
0
def test_discover_packages():
    # check without any extensions
    with patch(
            'colcon_core.package_discovery.get_package_discovery_extensions',
            return_value={},
    ) as get_extensions:
        with patch('colcon_core.package_discovery.logger.warning') as warn:
            descs = discover_packages(None, None)
    assert get_extensions.call_count == 1
    warn.assert_called_once_with('No package discovery extensions found')
    assert descs == set()

    with EntryPointContext(
            extension1=Extension1,
            extension2=Extension2,
            extension3=Extension3,
            extension4=Extension4,
    ):
        extensions = get_package_discovery_extensions()
        assert len(extensions) == 4

        # check without any parameters
        extensions['extension1'].discover = Mock(
            return_value={PackageDescriptor('/extension1/pkg1')})
        extensions['extension2'].discover = Mock(
            return_value={PackageDescriptor('/extension2/pkg1')})

        descs = discover_packages(None, None, discovery_extensions=extensions)
        assert len(descs) == 2
        expected_path = '/extension1/pkg1'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)
        expected_path = '/extension2/pkg1'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)

        # check with parameters
        extensions['extension3'].has_parameters = Mock(return_value=True)
        extensions['extension3'].discover = Mock(
            return_value={
                PackageDescriptor('/extension3/pkg1'),
                PackageDescriptor('/extension3/pkg2')
            })

        descs = discover_packages(None, None, discovery_extensions=extensions)
        assert len(descs) == 2
        expected_path = '/extension3/pkg1'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)
        expected_path = '/extension3/pkg2'.replace('/', os.sep)
        assert expected_path in (str(d.path) for d in descs)
 def test_dependencies_changed(self):
     package_1_desc = PackageDescriptor('fake/path')
     package_1_desc.name = 'package1'
     package_1_desc.dependencies['run'] = [DependencyDescriptor('foo')]
     package_1 = PackageDecorator(package_1_desc)
     decorators = [package_1]
     self.assertTrue(
         package_dependencies_changed(self.path_context, decorators))
     update_dependencies_cache(self.path_context)
     package_1_desc.dependencies['run'] = [
         DependencyDescriptor('foo'), 'baz'
     ]
     package_1 = PackageDecorator(package_1_desc)
     decorators = [package_1]
     self.assertTrue(
         package_dependencies_changed(self.path_context, decorators))
Exemple #14
0
def test_discover():
    extension = PathPackageDiscovery()
    args = Mock()
    args.paths = None
    assert extension.discover(args=args, identification_extensions={}) == set()

    args.paths = [
        '/empty/path', '/skip/path', '/same/path', '/same/path/../path',
        '/other/path'
    ]
    with patch('colcon_core.package_discovery.path.identify',
               side_effect=identify):
        descs = extension.discover(args=args, identification_extensions={})
        assert descs == {
            PackageDescriptor(os.path.realpath('/same/path')),
            PackageDescriptor(os.path.realpath('/other/path'))
        }
Exemple #15
0
def test_constructor():
    d = PackageDescriptor('/some/path')
    assert d.path == Path('/some/path')
    assert d.type is None
    assert d.name is None
    assert len(d.dependencies.keys()) == 0
    assert len(d.hooks) == 0
    assert len(d.metadata.keys()) == 0
def test_no_augmentation():
    augmentation_extension = GitPackageAugmentation()

    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        desc = PackageDescriptor(basepath)
        assert not desc.metadata

        augmentation_extension.augment_package(desc)
        assert 'vcs_type' not in desc.metadata
Exemple #17
0
def test_update_descriptor():
    desc = PackageDescriptor('/some/path')
    assert len(desc.dependencies) == 0
    assert len(desc.hooks) == 0
    assert len(desc.metadata) == 0

    data = {
        'build-dependencies': {'b1', 'b2'},
        'test-dependencies': {'t1'},
    }
    update_descriptor(desc, data)
    assert len(desc.dependencies) == 2
    assert 'build' in desc.dependencies.keys()
    assert desc.dependencies['build'] == {'b1', 'b2'}
    assert 'test' in desc.dependencies.keys()
    assert desc.dependencies['test'] == {'t1'}

    data = {
        'dependencies': {'d1'},
        'hooks': ['hook1', 'hook2'],
        'key': 'value',
    }
    update_descriptor(desc, data, additional_argument_names=['*'])
    assert len(desc.dependencies) == 3
    assert 'build' in desc.dependencies.keys()
    assert desc.dependencies['build'] == {'d1', 'b1', 'b2'}
    assert 'run' in desc.dependencies.keys()
    assert desc.dependencies['run'] == {'d1'}
    assert 'test' in desc.dependencies.keys()
    assert desc.dependencies['test'] == {'d1', 't1'}

    assert len(desc.hooks) == 2
    assert desc.hooks == ['hook1', 'hook2']

    assert len(desc.metadata) == 1
    assert 'key' in desc.metadata
    assert desc.metadata['key'] == 'value'

    data = {
        'other': 'value',
        'some': 'value',
    }
    update_descriptor(
        desc, data, additional_argument_names=['some', 'unknown'])
    assert len(desc.metadata) == 2
    assert 'other' not in desc.metadata
    assert 'some' in desc.metadata
    assert desc.metadata['some'] == 'value'

    data = {
        'name': 'foo',
        'type': 'cmake',
    }
    update_descriptor(desc, data)
    assert desc.name == 'foo'
    assert desc.type == 'cmake'
Exemple #18
0
async def test_bundle():
    pkg = PackageDescriptor('package/path')
    pkg.name = 'MyPackageName'
    pkg.dependencies['run'] = {
        DependencyDescriptor('source_pkg'),
        DependencyDescriptor('other_pkg'),
        DependencyDescriptor('system_pkg')
    }
    installers = {
        'rdmanifest': MagicMock(),
        'system': MagicMock(),
        'other': MagicMock()
    }
    top_level_args = MagicMock(build_base='build/base',
                               install_base='install/base',
                               bundle_base='bundle/base')
    args = BundlePackageArguments(pkg, installers, top_level_args)
    args.ros_distribution = 'kinetic'
    args.exclude_ros_base = True

    context = TaskContext(pkg=pkg, args=args, dependencies={})
    task = RosBundle()
    task.set_context(context=context)

    # Concise read on why it's patched this way.
    # http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch
    with patch('colcon_ros_bundle.task.ros_bundle.RosdepWrapper'
               ) as wrapper:  # noqa: E501
        wrapper().get_rule.side_effect = _get_rule_side_effect
        wrapper().resolve.side_effect = _resolve_side_effect
        await task.bundle()

    installers['rdmanifest'].add_to_install_list.assert_called_with(
        'source_pkg', {
            's': 'ource',
            'uri': 'rdmanifest'
        })
    installers['other'].add_to_install_list.assert_called_with(
        'other_pkg_name')
    installers['system'].add_to_install_list.assert_called_with(
        'system_pkg_name')
Exemple #19
0
def test_discover_with_wildcards():
    with TemporaryDirectory(prefix='test_colcon_') as prefix_path:
        prefix_path = Path(prefix_path)
        path_one = prefix_path / 'one' / 'path'
        path_two = prefix_path / 'two' / 'path'
        path_three = prefix_path / 'three' / 'path'
        path_one.mkdir(parents=True)
        path_two.mkdir(parents=True)
        path_three.mkdir(parents=True)

        extension = PathPackageDiscovery()
        args = Mock()
        args.paths = [str(prefix_path / '*' / 'path')]
        with patch('colcon_core.package_discovery.path.identify',
                   side_effect=identify):
            descs = extension.discover(args=args, identification_extensions={})
            assert descs == {
                PackageDescriptor(os.path.realpath(str(path_one))),
                PackageDescriptor(os.path.realpath(str(path_two))),
                PackageDescriptor(os.path.realpath(str(path_three)))
            }
def test_augmentation():
    augmentation_extension = GitPackageAugmentation()

    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        repo = Repo.init(basepath)
        assert repo

        desc = PackageDescriptor(basepath)
        assert not desc.metadata

        augmentation_extension.augment_package(desc)
        assert desc.metadata['vcs_type'] == 'git'
async def test_task_test():
    with TemporaryDirectory(prefix='test_colcon_') as basepath:
        extension = BazelTestTask()

        desc = PackageDescriptor(basepath)
        desc.name = "test"

        args_verb = MockArgs(basepath)
        args_pkg = TestPackageArguments(desc, args_verb)
        args_pkg.path = basepath
        args_pkg.build_base = args_verb.build_base
        args_pkg.install_base = args_verb.install_base
        args_pkg.merge_install = args_verb.merge_install
        args_pkg.test_result_base = args_verb.test_result_base

        context = TaskContext(pkg=desc, args=args_pkg, dependencies=set())

        extension.set_context(context=context)
        ret = await extension.test()

        assert ret
Exemple #22
0
def test_str():
    d = PackageDescriptor('/some/path')
    d.type = 'custom-type'
    d.name = 'custom-name'
    d.dependencies['build'].add('build-depend')
    d.dependencies['run'].add('run-depend')
    d.hooks += ('hook-a', 'hook-b')
    d.metadata['key'] = 'value'
    s = str(d)
    assert s.startswith('{')
    assert s.endswith('}')
    assert 'path: ' in s
    assert '/some/path'.replace('/', os.sep) in s
    assert 'type: ' in s
    assert 'custom-type' in s
    assert 'name: ' in s
    assert 'custom-name' in s
    assert 'dependencies: ' in s
    assert 'build-depend' in s
    assert 'run-depend' in s
    assert 'hooks: ' in s
    assert 'hook-a' in s
    assert 'metadata: ' in s
    assert 'value' in s
def test_pytest_match():
    extension = PytestPythonTestingStep()
    env = {}
    desc = PackageDescriptor('/dev/null')
    context = TaskContext(pkg=desc, args=None, dependencies=None)

    desc.name = 'pkg-name'
    desc.type = 'python'

    # no test requirements
    desc.metadata['get_python_setup_options'] = lambda env: {}
    assert not extension.match(context, env, get_setup_data(desc, env))

    # pytest not in tests_require
    desc.metadata['get_python_setup_options'] = lambda env: {
        'tests_require': ['nose'],
    }
    assert not extension.match(context, env, get_setup_data(desc, env))

    # pytest not in extras_require.test
    desc.metadata['get_python_setup_options'] = lambda env: {
        'extras_require': {
            'test': ['nose']
        },
    }
    assert not extension.match(context, env, get_setup_data(desc, env))

    # pytest in tests_require
    desc.metadata['get_python_setup_options'] = lambda env: {
        'tests_require': ['pytest'],
    }
    assert extension.match(context, env, get_setup_data(desc, env))

    # pytest in extras_require.test
    desc.metadata['get_python_setup_options'] = lambda env: {
        'extras_require': {
            'test': ['pytest']
        },
    }
    assert extension.match(context, env, get_setup_data(desc, env))
Exemple #24
0
def test_get_dependencies():
    d1 = PackageDescriptor('/some/path')
    d1.name = 'self'
    d1.dependencies['build'].add('build-depend')
    d1.dependencies['build'].add('depend')
    d1.dependencies['run'].add('run-depend')
    d1.dependencies['run'].add('depend')
    assert d1.get_dependencies() == {'build-depend', 'run-depend', 'depend'}

    d1.dependencies['test'].add('self')
    assert d1.get_dependencies(categories=('build', )) == \
        {'build-depend', 'depend'}

    with pytest.raises(AssertionError) as e:
        d1.get_dependencies()
    assert "'self'" in str(e.value)
Exemple #25
0
def identify(
    extensions: Dict[  # actually an OrderedDict
        int,  # priority
        Dict[str, PackageIdentificationExtensionPoint],  # an OrderedDict
    ],
    path: str,
) -> ReturnType:
    """
    Identify the package in the given path.

    :param extensions: dict of extensions
    :param path: The path
    """
    desc = PackageDescriptor(path)

    for extensions_same_prio in extensions.values():
        result = _identify(extensions_same_prio, desc)

        # continue with next priority level if no information was contributed
        if result is None:
            continue

        # skip location since identification is ambiguous
        if result is False:
            raise IgnoreLocationException()

        assert isinstance(result, PackageDescriptor), result
        if result.identifies_package():
            return result

        # use incrementally populated descriptor for next priority level
        desc = result

    if getattr(desc, 'type', None) or getattr(desc, 'name', None):
        logger.warning(
            "package '{desc.path}' has type or name but is incomplete".
            format_map(locals()))
    return None
Exemple #26
0
def test_get_packages():
    args = Namespace()
    d1 = PackageDescriptor('/some/path')
    d1.name = 'one'
    d2 = PackageDescriptor('/other/path')
    d2.name = 'two'
    with patch('colcon_core.package_selection.discover_packages',
               return_value=[d1, d2]):
        decos = get_packages(args)
    assert len(decos) == 2
    assert decos[0].descriptor.name == 'one'
    assert decos[0].selected is True
    assert decos[1].descriptor.name == 'two'
    assert decos[1].selected is True

    d2.name = 'one'
    with patch('colcon_core.package_selection.discover_packages',
               return_value=[d1, d2]):
        with pytest.raises(RuntimeError) as e:
            get_packages(args)
        assert 'Duplicate package names not supported:' in str(e.value)
        assert '- one:' in str(e.value)
        assert '- {sep}some{sep}path'.format(sep=os.sep) in str(e.value)
        assert '- {sep}other{sep}path'.format(sep=os.sep) in str(e.value)
Exemple #27
0
def test__identify():
    desc_path_only = PackageDescriptor('/some/path')
    with EntryPointContext(
            extension1=Extension1,
            extension2=Extension2,
            extension3=Extension3,
            extension4=Extension4,
    ):
        # valid result
        extensions = get_package_identification_extensions()[100]
        extensions['extension2'].identify = Mock()
        extensions['extension4'].identify = identify_name_and_type
        desc = _identify(extensions, desc_path_only)
        assert isinstance(desc, PackageDescriptor)
        assert str(desc.path) == '/some/path'.replace('/', os.sep)
        assert desc.name == 'name'
        assert desc.type == 'type'

        # no results
        extensions = get_package_identification_extensions()[100]
        extensions['extension2'].identify = Mock()
        extensions['extension4'].identify = Mock()
        desc = _identify(extensions, desc_path_only)
        assert desc is None

        # multiple different results
        extensions = get_package_identification_extensions()[100]
        extensions['extension2'].identify = identify_name
        extensions['extension4'].identify = identify_type
        with patch(
                'colcon_core.package_identification.logger.warning') as warn:
            desc = _identify(extensions, desc_path_only)
            assert desc is False
            # the raised exception is catched and results in a warn message
            assert warn.call_count == 1
            assert len(warn.call_args[0]) == 1
            assert 'multiple matches' in warn.call_args[0][0]

        # invalid return value
        extensions = get_package_identification_extensions()[90]
        extensions['extension3'].identify = Mock(return_value=True)
        with patch('colcon_core.package_identification.logger.error') as error:
            desc = _identify(extensions, desc_path_only)
            assert desc is None
            # the raised exception is catched and results in an error message
            assert error.call_count == 1
            assert len(error.call_args[0]) == 1
            assert error.call_args[0][0].startswith(
                "Exception in package identification extension 'extension3' "
                "in '/some/path': identify() should return None\n".replace(
                    '/', os.sep))

        # skip location
        extensions = get_package_identification_extensions()[90]
        extensions['extension3'].identify = Mock(
            side_effect=IgnoreLocationException())
        with pytest.raises(IgnoreLocationException):
            _identify(extensions, desc_path_only)

        # raise exception
        extensions = get_package_identification_extensions()[90]
        extensions['extension3'].identify = Mock(
            side_effect=RuntimeError('custom exception'))
        with patch('colcon_core.package_identification.logger.error') as error:
            desc = _identify(extensions, desc_path_only)
            assert desc is None
            # the raised exception is catched and results in an error message
            assert error.call_count == 1
            assert len(error.call_args[0]) == 1
            assert error.call_args[0][0].startswith(
                "Exception in package identification extension 'extension3' "
                "in '/some/path': custom exception\n".replace('/', os.sep))
Exemple #28
0
def test_magic_methods():
    d1 = PackageDescriptor('/some/path')
    d1.type = 'custom-type'
    d1.name = 'custom-name'
    d2 = PackageDescriptor('/some/path')
    d2.type = 'custom-type'
    d2.name = 'other-name'
    assert d1 != d2
    assert hash(d1) != hash(d2)

    d2.name = 'custom-name'
    assert d1 == d2
    assert hash(d1) == hash(d2)

    d1.dependencies['build'].add('build-depend')
    d2.hooks.append('hook')
    d2.metadata['key'] = 'value'
    assert d1 == d2
    assert hash(d1) == hash(d2)

    d2.type = 'other-type'
    assert d1 != d2
    assert hash(d1) != hash(d2)

    d2.type = 'custom-type'
    assert d1 == d2
    assert hash(d1) == hash(d2)

    d2.path = Path('/other/path')
    assert d1 != d2

    # comparing with other types always returns False
    assert d1 != []
Exemple #29
0
def test_get_recursive_dependencies():
    d = PackageDescriptor('/some/path')
    d.name = 'A'
    d.dependencies['build'].add('B')
    d.dependencies['run'].add('c')
    d.dependencies['test'].add('d')

    d1 = PackageDescriptor('/other/path')
    d1.name = 'B'
    d1.dependencies['build'].add('e')
    d1.dependencies['run'].add('F')
    d1.dependencies['test'].add('G')

    d2 = PackageDescriptor('/another/path')
    d2.name = 'd'

    d3 = PackageDescriptor('/yet-another/path')
    d3.name = 'F'
    d3.dependencies['build'].add('h')
    d3.dependencies['test'].add('G')
    d3.dependencies['test'].add('I')

    d4 = PackageDescriptor('/more/path')
    d4.name = 'G'
    d4.dependencies['test'].add('I')

    d5 = PackageDescriptor('/yet-more/path')
    d5.name = 'I'
    # circular dependencies should be ignored
    d5.dependencies['run'].add('A')

    rec_deps = d.get_recursive_dependencies({d, d1, d2, d3, d4, d5},
                                            direct_categories=('build', 'run'),
                                            recursive_categories=('run',
                                                                  'test'))
    assert rec_deps == {
        # direct dependencies
        'B',
        # recursive dependencies
        'F',
        'G',
        'I',
    }
Exemple #30
0
def update_descriptor(desc: PackageDescriptor,
                      data: dict,
                      *,
                      additional_argument_names=None):
    """
    Update the package descriptor with additional information.

    For the keys `name` and `type` the values from `data` are set on the
    descriptor attributes with the same names.
    For the key `dependencies` the values are being added to the dependencies
    in each of the following categories: `build`, `run`, and `test`.
    For the keys `build_dependencies`, `run_dependencies`, and
    `test_dependencies` the values are being added to the dependencies in the
    category with the same name.
    For the key `hooks` the values are being added to the list of hooks.

    Any key-value pair not explicitly mentioned above is being used to update
    the metadata if the key is in the list of additional argument names.
    See :function:`update_metadata` for details how the metadata is updated.

    If the additional argument names is a list with the single value `*` all
    keys not explicitly mentioned above are being used to update the metadata.

    :param desc: the package descriptor
    :param data: The dictionary with additional information
    :param additional_argument_names: A dict of option names to destination
      names or a list of argument names
    """
    # explicit key updates
    try:
        desc.name = data['name']
    except KeyError:
        pass
    try:
        desc.type = data['type']
    except KeyError:
        pass
    dep_types = ('build', 'run', 'test')
    # transfer generic dependencies to each specific type
    if 'dependencies' in data:
        for d in data['dependencies']:
            for dep_type in dep_types:
                desc.dependencies[dep_type].add(d)
    # transfer type specific dependencies
    for dep_type in dep_types:
        key = '{dep_type}-dependencies'.format_map(locals())
        if key in data:
            for d in data[key]:
                desc.dependencies[dep_type].add(d)

    # transfer hooks
    if 'hooks' in data:
        for d in data['hooks']:
            desc.hooks.append(d)

    # transfer any other metadata
    if additional_argument_names == ['*']:
        additional_argument_names = []
        # skip any of the already explicitly handled names
        ignored_names = ['name', 'type', 'dependencies', 'hooks']
        for dep_type in dep_types:
            ignored_names.append('{dep_type}-dependencies'.format_map(
                locals()))
        for name in data.keys():
            if name in ignored_names:
                continue
            additional_argument_names.append(name)
    if isinstance(additional_argument_names, list):
        additional_argument_names = OrderedDict([
            (name, name) for name in additional_argument_names
        ])
    for option, dest in (additional_argument_names or {}).items():
        if option in data:
            update_metadata(desc, dest, data[option])