예제 #1
0
    def test_system_pip_command(self):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        pip_command = os.path.join(os.path.sep, 'usr', 'bin', 'pip3')
        self.assertEqual(plugin.system_pip_command, pip_command)

        # NOTE(SamYaple): python2 pip test
        self.options.python_version = 'python2'
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        pip_command = os.path.join(os.path.sep, 'usr', 'bin', 'pip')
        self.assertEqual(plugin.system_pip_command, pip_command)
예제 #2
0
    def test_build(self, mock_base_build, mock_run, mock_run_output):
        self.options.requirements = 'requirements.txt'
        self.options.constraints = 'constraints.txt'
        self.options.python_packages = ['test', 'packages']

        class TempDir(tempfile.TemporaryDirectory):
            def __enter__(self):
                project_whl_path = os.path.join(self.name, 'project.whl')
                open(project_whl_path, 'w').close()
                return super().__enter__()

        patcher = mock.patch('tempfile.TemporaryDirectory',
                             new=mock.Mock(wraps=TempDir))
        patcher.start()
        self.addCleanup(patcher.stop)

        mock_run_output.return_value = 'yaml (1.2)\bextras (1.0)'

        os.environ = {}
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        def build_side_effect():
            open(os.path.join(plugin.builddir, 'setup.py'), 'w').close()

        mock_base_build.side_effect = build_side_effect

        requirements_path = os.path.join(plugin.sourcedir, 'requirements.txt')
        constraints_path = os.path.join(plugin.sourcedir, 'constraints.txt')

        pip_command = [
            os.path.join(plugin.installdir, 'usr', 'bin', 'python3'), '-m',
            'pip'
        ]

        pip_wheel = [
            'wheel', '--disable-pip-version-check', '--no-index',
            '--find-links', plugin._python_package_dir, '--constraint',
            constraints_path, '--wheel-dir', mock.ANY
        ]

        pip_install = [
            'install', '--user', '--no-compile', '--disable-pip-version-check',
            '--no-index', '--find-links', plugin._python_package_dir,
            '--constraint', constraints_path
        ]

        calls = [
            mock.call(
                pip_command + pip_wheel +
                ['--requirement', requirements_path, '.', 'test', 'packages'],
                cwd=plugin.builddir,
                env=mock.ANY),
            mock.call(tests.ContainsList(pip_command + pip_install +
                                         ['project.whl']),
                      env=mock.ANY),
        ]
        plugin.build()
        mock_run.assert_has_calls(calls)
예제 #3
0
    def test_process_dependency_links(self):
        self.options.process_dependency_links = True
        plugin = python.PythonPlugin("test-part", self.options, self.project)
        setup_directories(plugin, self.options.python_version)
        plugin.pull()
        plugin.build()

        pip_download = self.mock_pip.return_value.download
        self.assertThat(pip_download.call_count, Equals(2))
        pip_download.assert_has_calls([
            mock.call(
                [],
                constraints=set(),
                process_dependency_links=True,
                requirements=set(),
                setup_py_dir=None,
            ),
            mock.call(
                [],
                constraints=set(),
                process_dependency_links=True,
                requirements=set(),
                setup_py_dir=plugin.sourcedir,
            ),
        ])

        pip_install = self.mock_pip.return_value.install
        self.assertThat(pip_install.call_count, Equals(2))
        pip_install.assert_has_calls([
            mock.call([],
                      upgrade=True,
                      process_dependency_links=True,
                      install_deps=False),
            mock.call([],
                      upgrade=True,
                      process_dependency_links=True,
                      install_deps=False),
        ])

        pip_wheel = self.mock_pip.return_value.wheel
        self.assertThat(pip_wheel.call_count, Equals(2))
        # Double check to avoid annotating the magic methods.
        pip_wheel.assert_has_calls([
            mock.call(
                [],
                constraints=set(),
                process_dependency_links=True,
                requirements=set(),
                setup_py_dir=None,
            )
        ])
        pip_wheel.assert_has_calls([
            mock.call(
                [],
                constraints=set(),
                process_dependency_links=True,
                requirements=set(),
                setup_py_dir=plugin.sourcedir,
            )
        ])
예제 #4
0
    def test_constraints_file_missing(self):
        setattr(self.options, self.property, self.file_path)

        plugin = python.PythonPlugin("test-part", self.options, self.project_options)
        setup_directories(plugin, self.options.python_version)

        self.assertRaises(python.SnapcraftPluginPythonFileMissing, plugin.pull)
예제 #5
0
    def test_plugin_stage_packages_python3(self):
        self.options.python_version = "python3"

        plugin = python.PythonPlugin("test-part", self.options, self.project)
        self.assertThat(
            plugin.plugin_stage_packages, Equals(["python3", "python3-distutils"])
        )
예제 #6
0
    def test_process_dependency_links(self):
        self.options.process_dependency_links = True
        plugin = python.PythonPlugin("test-part", self.options, self.project_options)
        setup_directories(plugin, self.options.python_version)
        plugin.pull()
        plugin.build()

        pip_download = self.mock_pip.return_value.download
        pip_download.assert_called_once_with(
            [],
            constraints=None,
            process_dependency_links=True,
            requirements=None,
            setup_py_dir=plugin.sourcedir,
        )

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_called_once_with(
            [], upgrade=True, process_dependency_links=True, install_deps=False
        )

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.assert_called_once_with(
            [],
            constraints=None,
            process_dependency_links=True,
            requirements=None,
            setup_py_dir=plugin.sourcedir,
        )
예제 #7
0
    def test_pull_with_nothing(self, mock_run, mock_run_output):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        plugin.pull()
        mock_run.assert_has_calls([])
예제 #8
0
 def test_process_dependency_links(self, run_mock, mock_run_output):
     self.options.process_dependency_links = True
     plugin = python.PythonPlugin('test-part', self.options,
                                  self.project_options)
     setup_directories(plugin, self.options.python_version)
     plugin.pull()
     self.assertIn('--process-dependency-links', run_mock.call_args[0][0])
예제 #9
0
 def test_missing_setup_path(self, mock_path_exists, mock_run,
                             mock_run_output):
     plugin = python.PythonPlugin('test-part', self.options,
                                  self.project_options)
     setup_directories(plugin, self.options.python_version)
     plugin.pull()
     self.assertFalse(mock_run.called)
예제 #10
0
    def test_no_python_packages_does_nothing(self):
        # This should be an error but given that we default to
        # 'source: .' and now that pip 10 has been released
        # we run into the need of fixing this situation.
        self.mock_pip.return_value.list.return_value = dict()

        self.useFixture(fixture_setup.CleanEnvironment())
        plugin = python.PythonPlugin("test-part", self.options, self.project_options)
        setup_directories(plugin, self.options.python_version, create_setup_py=False)

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.return_value = []

        plugin.build()

        # Pip should not attempt to download again in build (only pull)
        pip_download = self.mock_pip.return_value.download
        pip_download.assert_not_called()

        pip_wheel.assert_called_once_with(
            [],
            constraints=None,
            process_dependency_links=False,
            requirements=None,
            setup_py_dir=None,
        )

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_not_called()
예제 #11
0
    def test_plugin_stage_packages_python2_bionic(self):
        self.options.python_version = "python2"
        self.mock_os_release.return_value.version_codename.return_value = "bionic"

        plugin = python.PythonPlugin("test-part", self.options,
                                     self.project_options)
        self.assertThat(plugin.plugin_stage_packages, Equals(["python"]))
예제 #12
0
    def test_build_creates_correct_sitecustomize(self, mock_base_build,
                                                 mock_run, mock_run_output):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        plugin.build()

        expected_sitecustomize = (
            'import site\n'
            'import os\n'
            '\n'
            'snap_dir = os.getenv("SNAP")\n'
            'snapcraft_stage_dir = os.getenv("SNAPCRAFT_STAGE")\n'
            'snapcraft_part_install = os.getenv("SNAPCRAFT_PART_INSTALL")\n'
            '\n'
            'for d in (snap_dir, snapcraft_stage_dir, '
            'snapcraft_part_install):\n'
            '    if d:\n'
            '        site_dir = os.path.join(d, '
            '"lib/python3.5/site-packages")\n'
            '        site.addsitedir(site_dir)\n'
            '\n'
            'if snap_dir:\n'
            '    site.ENABLE_USER_SITE = False')

        site_path = glob(
            os.path.join(plugin.installdir, 'usr', 'lib', 'python*',
                         'sitecustomize.py'))[0]
        self.assertThat(site_path, FileContains(expected_sitecustomize))
예제 #13
0
    def test_pull(self, mock_run):
        self.options.requirements = 'requirements.txt'
        self.options.constraints = 'constraints.txt'
        self.options.python_packages = ['test', 'packages']

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        requirements_path = os.path.join(plugin.sourcedir, 'requirements.txt')
        constraints_path = os.path.join(plugin.sourcedir, 'constraints.txt')

        pip_download = [
            'pip', 'download', '--disable-pip-version-check', '--dest',
            plugin._python_package_dir, '--constraint', constraints_path
        ]

        calls = [
            mock.call(pip_download + ['--requirement', requirements_path],
                      env=mock.ANY),
            mock.call(pip_download + ['test', 'packages'], env=mock.ANY),
            mock.call(pip_download + ['.'], cwd=plugin.sourcedir,
                      env=mock.ANY),
        ]
        plugin.pull()
        mock_run.assert_has_calls(calls)
예제 #14
0
    def test_pip_with_url(self):
        self.options.requirements = 'https://test.com/requirements.txt'
        self.options.constraints = 'http://test.com/constraints.txt'

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)
        plugin.pull()
        plugin.build()

        pip_download = self.mock_pip.return_value.download
        pip_download.assert_called_once_with(
            [],
            constraints={self.options.constraints},
            process_dependency_links=False,
            requirements={self.options.requirements},
            setup_py_dir=plugin.sourcedir)

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_called_once_with([],
                                            upgrade=True,
                                            process_dependency_links=False,
                                            install_deps=False)

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.assert_called_once_with(
            [],
            constraints={self.options.constraints},
            process_dependency_links=False,
            requirements={self.options.requirements},
            setup_py_dir=plugin.sourcedir)
예제 #15
0
    def test_pull_without_requirements(self, mock_run):
        self.options.requirements = ''
        self.options.constraints = 'constraints.txt'
        self.options.python_packages = ['test', 'packages']

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        constraints_path = os.path.join(plugin.sourcedir, 'constraints.txt')

        pip_command = [
            os.path.join(plugin.installdir, 'usr', 'bin', 'python3'), '-m',
            'pip'
        ]

        pip_download = [
            'download', '--disable-pip-version-check', '--dest',
            plugin._python_package_dir, '--constraint', constraints_path
        ]

        calls = [
            mock.call(pip_command + pip_download + ['.', 'test', 'packages'],
                      cwd=plugin.sourcedir,
                      env=mock.ANY),
        ]
        plugin.pull()
        mock_run.assert_has_calls(calls)
예제 #16
0
    def test_pip_with_url(self, mock_run, mock_run_output):
        self.options.requirements = 'https://test.com/requirements.txt'
        self.options.constraints = 'http://test.com/constraints.txt'

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        pip_command = [
            os.path.join(plugin.installdir, 'usr', 'bin', 'python3'), '-m',
            'pip'
        ]

        pip_download = [
            'download', '--disable-pip-version-check', '--dest',
            plugin._python_package_dir, '--constraint',
            'http://test.com/constraints.txt'
        ]

        calls = [
            mock.call(
                pip_command + pip_download +
                ['--requirement', 'https://test.com/requirements.txt', '.'],
                cwd=plugin.sourcedir,
                env=mock.ANY),
        ]
        plugin.pull()
        mock_run.assert_has_calls(calls)
예제 #17
0
    def test_pip_with_url(self):
        self.options.requirements = 'https://test.com/requirements.txt'
        self.options.constraints = 'http://test.com/constraints.txt'

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        # Patch requests so we don't hit the network when the requirements
        # and constraints files are downloaded to save their contents in the
        # manifest.
        with mock.patch('requests.get'):
            plugin.pull()
            plugin.build()

        pip_download = self.mock_pip.return_value.download
        pip_download.assert_called_once_with(
            [], constraints={self.options.constraints},
            process_dependency_links=False,
            requirements={self.options.requirements},
            setup_py_dir=plugin.sourcedir)

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_called_once_with(
            [], upgrade=True, process_dependency_links=False,
            install_deps=False)

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.assert_called_once_with(
            [], constraints={self.options.constraints},
            process_dependency_links=False,
            requirements={self.options.requirements},
            setup_py_dir=plugin.sourcedir)
예제 #18
0
    def test_plugin_stage_packages_python2_bionic(self):
        self.options.python_version = 'python2'
        self.mock_os_release.return_value.version_codename.return_value = (
            'bionic')

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        self.assertThat(plugin.plugin_stage_packages, Equals(['python']))
예제 #19
0
    def test_env(self):
        plugin = python.PythonPlugin("test-part", self.options, self.project_options)
        expected_env = []
        env = plugin.env("/testpath")
        self.assertListEqual(expected_env, env)

        env_missing_path = plugin.env("/testpath")
        self.assertTrue("PYTHONPATH=/testpath" not in env_missing_path)
예제 #20
0
    def test_get_manifest_with_constraints_url(self):
        self.options.constraints = [self.source]
        plugin = python.PythonPlugin("test-part", self.options, self.project)
        setup_directories(plugin, self.options.python_version)

        plugin.build()

        self.assertThat(plugin.get_manifest()["constraints-contents"],
                        Equals(["Test fake file"]))
예제 #21
0
    def test_clean_pull(self, mock_run):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)

        # Pretend pip downloaded packages
        os.makedirs(os.path.join(plugin.partdir, 'packages'))
        plugin.clean_pull()
        self.assertFalse(
            os.path.isdir(os.path.join(plugin.partdir, 'packages')))
예제 #22
0
 def test_fileset_ignores(self):
     plugin = python.PythonPlugin('test-part', self.options,
                                  self.project_options)
     expected_fileset = [
         '-bin/pip*', '-bin/easy_install*', '-bin/wheel', '-**/__pycache__',
         '-**/*.pyc', '-lib/python*/site-packages/*/RECORD'
     ]
     fileset = plugin.snap_fileset()
     self.assertListEqual(expected_fileset, fileset)
예제 #23
0
    def test_build(self, mock_base_build):
        self.options.requirements = "requirements.txt"
        self.options.constraints = "constraints.txt"
        self.options.python_packages = ["test", "packages"]

        packages = collections.OrderedDict()
        packages["yaml"] = "1.2"
        packages["extras"] = "1.0"
        self.mock_pip.return_value.list.return_value = packages

        self.useFixture(fixture_setup.CleanEnvironment())
        plugin = python.PythonPlugin("test-part", self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        for file_name in (self.options.requirements, self.options.constraints):
            path = os.path.join(plugin.sourcedir, file_name)
            open(path, "w").close()

        requirements_path = os.path.join(plugin.builddir, "requirements.txt")
        constraints_path = os.path.join(plugin.builddir, "constraints.txt")

        def build_side_effect():
            open(os.path.join(plugin.builddir, "setup.py"), "w").close()
            os.mkdir(os.path.join(plugin.builddir, "dist"))
            open(os.path.join(plugin.builddir, "dist", "package.tar"),
                 "w").close()
            open(requirements_path, "w").close()
            open(constraints_path, "w").close()

        mock_base_build.side_effect = build_side_effect

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.return_value = ["foo", "bar"]

        plugin.build()

        # Pip should not attempt to download again in build (only pull)
        pip_download = self.mock_pip.return_value.download
        pip_download.assert_not_called()

        pip_wheel.assert_called_once_with(
            ["test", "packages"],
            constraints={constraints_path},
            process_dependency_links=False,
            requirements={requirements_path},
            setup_py_dir=plugin.builddir,
        )

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_called_once_with(
            ["foo", "bar"],
            process_dependency_links=False,
            upgrade=True,
            install_deps=False,
        )
예제 #24
0
    def test_get_manifest_with_constraints_url(self, _, mock_run_output):
        self.options.constraints = self.source
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        plugin.build()

        self.assertThat(plugin.get_manifest()['constraints-contents'],
                        Equals('Test fake file'))
예제 #25
0
    def test_get_manifest_with_requirements_url(self):
        self.options.requirements = self.source
        plugin = python.PythonPlugin("test-part", self.options, self.project_options)
        setup_directories(plugin, self.options.python_version)

        plugin.build()

        self.assertThat(
            plugin.get_manifest()["requirements-contents"], Equals("Test fake file")
        )
예제 #26
0
    def test_build_fixes_python_shebangs(self, run_mock):
        if self.options.python_version == 'python2':
            py_version_short = 'python2'
            py_version_long = 'python2'
        elif self.options.python_version == 'python3':
            py_version_short = 'python3'
            py_version_long = 'python3.5'

        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        os.makedirs(plugin.sourcedir)
        open(os.path.join(plugin.sourcedir, 'setup.py'), 'w').close()
        os.makedirs(os.path.join(plugin.installdir, 'bin'))
        os.makedirs(os.path.join(
            plugin.installdir, 'usr', 'lib', py_version_long, 'dist-packages'))
        os.makedirs(os.path.join(
            plugin.installdir, 'usr', 'include', py_version_long))

        # Place a few files with bad shebangs, and some files that shouldn't be
        # changed.
        files = [
            {
                'path': os.path.join(plugin.installdir, 'example.py'),
                'contents': '#!/foo/bar/baz/python',
                'expected': '#!/usr/bin/env python',
            },
            {
                'path': os.path.join(plugin.installdir, 'bin/another_example'),
                'contents': '#!/foo/baz/' + py_version_short,
                'expected': '#!/usr/bin/env ' + py_version_short,
            },
            {
                'path': os.path.join(plugin.installdir, 'foo'),
                'contents': 'foo',
                'expected': 'foo',
            },
            {
                'path': os.path.join(plugin.installdir, 'bar'),
                'contents': 'bar\n#!/usr/bin/python3',
                'expected': 'bar\n#!/usr/bin/python3',
            }
        ]

        for file_info in files:
            with open(file_info['path'], 'w') as f:
                f.write(file_info['contents'])

        plugin.build()

        for file_info in files:
            with open(os.path.join(plugin.installdir,
                                   file_info['path']), 'r') as f:
                self.assertEqual(f.read(), file_info['expected'])
예제 #27
0
    def test_env(self):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        expected_env = [
            'PYTHONUSERBASE=/testpath',
            'PYTHONHOME=/testpath/usr',
        ]
        env = plugin.env('/testpath')
        self.assertListEqual(expected_env, env)

        env_missing_path = plugin.env('/testpath')
        self.assertTrue('PYTHONPATH=/testpath' not in env_missing_path)
예제 #28
0
    def test_build(self, mock_base_build):
        self.options.requirements = 'requirements.txt'
        self.options.constraints = 'constraints.txt'
        self.options.python_packages = ['test', 'packages']

        packages = collections.OrderedDict()
        packages['yaml'] = '1.2'
        packages['extras'] = '1.0'
        self.mock_pip.return_value.list.return_value = packages

        self.useFixture(fixture_setup.CleanEnvironment())
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        for file_name in (self.options.requirements, self.options.constraints):
            path = os.path.join(plugin.sourcedir, file_name)
            open(path, 'w').close()

        requirements_path = os.path.join(plugin.builddir, 'requirements.txt')
        constraints_path = os.path.join(plugin.builddir, 'constraints.txt')

        def build_side_effect():
            open(os.path.join(plugin.builddir, 'setup.py'), 'w').close()
            os.mkdir(os.path.join(plugin.builddir, 'dist'))
            open(os.path.join(plugin.builddir, 'dist', 'package.tar'),
                 'w').close()
            open(requirements_path, 'w').close()
            open(constraints_path, 'w').close()

        mock_base_build.side_effect = build_side_effect

        pip_wheel = self.mock_pip.return_value.wheel
        pip_wheel.return_value = ['foo', 'bar']

        plugin.build()

        # Pip should not attempt to download again in build (only pull)
        pip_download = self.mock_pip.return_value.download
        pip_download.assert_not_called()

        pip_wheel.assert_called_once_with(['test', 'packages'],
                                          constraints={constraints_path},
                                          process_dependency_links=False,
                                          requirements={requirements_path},
                                          setup_py_dir=plugin.builddir)

        pip_install = self.mock_pip.return_value.install
        pip_install.assert_called_once_with(['foo', 'bar'],
                                            process_dependency_links=False,
                                            upgrade=True,
                                            install_deps=False)
예제 #29
0
    def test_pull_with_setup_py(self):
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)

        plugin.pull()

        pip_download = self.mock_pip.return_value.download
        pip_download.assert_called_once_with(
            [], constraints=None, process_dependency_links=False,
            requirements=None, setup_py_dir=plugin.sourcedir)

        self.mock_pip.return_value.wheel.assert_not_called()
        self.mock_pip.return_value.install.assert_not_called()
예제 #30
0
    def test_get_manifest_with_local_requirements(self, _, mock_run_output):
        self.options.requirements = 'requirements.txt'
        plugin = python.PythonPlugin('test-part', self.options,
                                     self.project_options)
        setup_directories(plugin, self.options.python_version)
        requirements_path = os.path.join(plugin.sourcedir, 'requirements.txt')
        with open(requirements_path, 'w') as requirements_file:
            requirements_file.write('testpackage1==1.0\n')
            requirements_file.write('testpackage2==1.2')

        plugin.build()

        self.assertThat(plugin.get_manifest()['requirements-contents'],
                        Equals('testpackage1==1.0\ntestpackage2==1.2'))