Skip to content

Commit

Permalink
Merge 114e585 into f305168
Browse files Browse the repository at this point in the history
  • Loading branch information
mriehl committed Jul 30, 2014
2 parents f305168 + 114e585 commit a745d97
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# This file is part of PyBuilder
#
# Copyright 2011 The PyBuilder Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest
from os.path import join

from integrationtest_support import IntegrationTestSupport


class Test (IntegrationTestSupport):

def test(self):
requirements = join(self.tmp_directory, "requirements.txt")
self.write_build_file("""
from pybuilder.core import use_plugin, init
use_plugin("python.core")
use_plugin("python.distutils")
name = "integration-test"
default_task = "publish"
@init
def init (project):
project.depends_on("spam")
project.depends_on_requirements("{0}")
project.depends_on("pyassert", url="https://github.com/downloads/halimath/pyassert/pyassert-0.2.2.tar.gz")
project.depends_on("eggs", "==0.2.3")
project.build_depends_on("eggy")
""".format(requirements))
self.create_directory("src/main/python/spam")
self.write_file("requirements.txt", """
awesome>=1.3.37
foo==42""")
self.write_file("src/main/python/standalone_module.py")
self.write_file("src/main/python/spam/__init__.py", "")
self.write_file("src/main/python/spam/eggs.py", """
def spam ():
pass
""")

reactor = self.prepare_reactor()
reactor.build()

self.assert_directory_exists("target/dist/integration-test-1.0-SNAPSHOT")
self.assert_directory_exists("target/dist/integration-test-1.0-SNAPSHOT/spam")
self.assert_file_exists("target/dist/integration-test-1.0-SNAPSHOT/standalone_module.py")
self.assert_file_empty("target/dist/integration-test-1.0-SNAPSHOT/spam/__init__.py")
self.assert_file_content("target/dist/integration-test-1.0-SNAPSHOT/spam/eggs.py", """
def spam ():
pass
""")

setup_py = "target/dist/integration-test-1.0-SNAPSHOT/setup.py"

self.assert_file_exists(setup_py)
self.assert_file_permissions(0o755, setup_py)
self.assert_file_content(setup_py, """#!/usr/bin/env python
from setuptools import setup
if __name__ == '__main__':
setup(
name = 'integration-test',
version = '1.0-SNAPSHOT',
description = '''''',
long_description = '''''',
author = "",
author_email = "",
license = '',
url = '',
scripts = [],
packages = ['spam'],
py_modules = ['standalone_module'],
classifiers = ['Development Status :: 3 - Alpha', 'Programming Language :: Python'],
entry_points={
'console_scripts':
[]
},
# data files
# package data
install_requires = [ "awesome>=1.3.37", "foo==42", "eggs==0.2.3", "spam" ],
dependency_links = [ "https://github.com/downloads/halimath/pyassert/pyassert-0.2.2.tar.gz" ],
zip_safe=True
)
""")


if __name__ == "__main__":
unittest.main()
35 changes: 35 additions & 0 deletions src/main/python/pybuilder/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,35 @@ def __hash__(self):
def __lt__(self, other):
return self.name < other.name

def is_a_requirements_file(self):
return False


class RequirementsFileDependency(object):
"""
Defines a dependency on a requirements file (requirements.txt).
"""
def __init__(self, filename):
self.filename = filename
self.name = self.filename
self.version = None
self.url = None

def __eq__(self, other):
return self.name == other.name and self.version == other.version and self.url == other.url

def __ne__(self, other):
return not(self == other)

def __hash__(self):
return 13 * hash(self.name) + 17 * hash(self.version)

def __lt__(self, other):
return self.name < other.name

def is_a_requirements_file(self):
return True


class Project(object):
"""
Expand Down Expand Up @@ -296,6 +325,12 @@ def depends_on(self, name, version=None, url=None):
def build_depends_on(self, name, version=None, url=None):
self._build_dependencies.add(Dependency(name, version, url))

def depends_on_requirements(self, file):
self._install_dependencies.add(RequirementsFileDependency(file))

def build_depends_on_requirements(self, file):
self._build_dependencies.add(RequirementsFileDependency(file))

@property
def manifest_included_files(self):
return self._manifest_included_files
Expand Down
9 changes: 8 additions & 1 deletion src/main/python/pybuilder/plugins/python/distutils_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,14 @@ def build_install_dependencies_string(project):
return ""

def format_single_dependency(dependency):
return '"%s%s"' % (dependency.name, build_dependency_version_string(dependency))
if dependency.is_a_requirements_file():
with open(dependency.filename, 'r') as requirements_file:
requirements = [d.strip("\n") for d in requirements_file.readlines()]
requirements = [d for d in requirements if d]
quoted_requirements = ['"%s"' % requirement for requirement in requirements]
return ", ".join(quoted_requirements)
else:
return '"%s%s"' % (dependency.name, build_dependency_version_string(dependency))

result = "install_requires = [ "
result += ", ".join(map(format_single_dependency, dependencies))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ def install_dependency(logger, project, dependency):
log_file = project.expand_path("$dir_install_logs", dependency.name)

if sys.platform.startswith("win"):
dependency = as_pip_argument(dependency)
pip_dependency = as_pip_argument(dependency)
else:
dependency = "'{0}'".format(as_pip_argument(dependency))
pip_command_line = "pip install {0}{1}".format(build_pip_install_options(project, dependency), dependency)
pip_dependency = "'{0}'".format(as_pip_argument(dependency))
pip_command_line = "pip install {0}{1}".format(build_pip_install_options(project, pip_dependency), pip_dependency)
exit_code = execute_command(pip_command_line, log_file, shell=True)
if exit_code != 0:
if project.get_property("verbose"):
Expand Down Expand Up @@ -125,6 +125,8 @@ def build_pip_install_options(project, dependency):


def as_pip_argument(dependency):
if dependency.is_a_requirements_file():
return "-r{0}".format(dependency.filename)
if dependency.url:
return dependency.url
return "{0}{1}".format(dependency.name, build_dependency_version_string(dependency))
Expand Down
19 changes: 19 additions & 0 deletions src/unittest/python/plugins/python/distutils_plugin_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.

try:
TYPE_FILE = file
except NameError:
from io import FileIO
TYPE_FILE = FileIO

import unittest

from mock import patch, MagicMock

from test_utils import PyBuilderTestCase
from pybuilder.core import Project, Author
from pybuilder.plugins.python.distutils_plugin import (build_data_files_string,
Expand Down Expand Up @@ -241,6 +249,17 @@ def test_should_render_console_scripts_when_property_is_set(self):
['release = zest.releaser.release:main','prerelease = zest.releaser.prerelease:main']
},""" in actual_setup_script)

@patch("pybuilder.plugins.python.distutils_plugin.open", create=True)
def test_should_render_runtime_dependencies_when_requirements_file_used(self, mock_open):
mock_open.return_value = MagicMock(spec=TYPE_FILE)
handle = mock_open.return_value.__enter__.return_value
handle.readlines.return_value = ["", "foo", "bar"]
self.project.depends_on_requirements("requirements.txt")

actual_setup_script = render_setup_script(self.project)

self.assertTrue('install_requires = [ "foo", "bar", "sometool" ],' in actual_setup_script)


class RenderManifestFileTest(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
from mockito import mock, when, verify, unstub, any as any_value
from mock import patch

from pybuilder.core import Project, Logger, Dependency
from pybuilder.core import (Project,
Logger,
Dependency,
RequirementsFileDependency)
from pybuilder.plugins.python.install_dependencies_plugin import (
install_runtime_dependencies,
install_build_dependencies,
Expand Down Expand Up @@ -54,6 +57,14 @@ def test_should_install_dependency_without_version(self):
verify(pybuilder.plugins.python.install_dependencies_plugin).execute_command(
"pip install 'spam'", any_value(), shell=True)

def test_should_install_requirements_file_dependency(self):
dependency = RequirementsFileDependency("requirements.txt")

install_dependency(self.logger, self.project, dependency)

verify(pybuilder.plugins.python.install_dependencies_plugin).execute_command(
"pip install '-rrequirements.txt'", any_value(), shell=True)

@patch("pybuilder.plugins.python.install_dependencies_plugin.sys.platform")
def test_should_install_dependency_without_version_on_windows_derivate(self, platform):
platform.return_value = "win32"
Expand Down Expand Up @@ -192,6 +203,7 @@ def tearDown(self):
def test_should_install_multiple_dependencies(self):
self.project.depends_on("spam")
self.project.depends_on("eggs")
self.project.depends_on_requirements("requirements.txt")

install_runtime_dependencies(self.logger, self.project)

Expand All @@ -201,6 +213,9 @@ def test_should_install_multiple_dependencies(self):
verify(
pybuilder.plugins.python.install_dependencies_plugin).execute_command("pip install 'eggs'",
any_value(), shell=True)
verify(
pybuilder.plugins.python.install_dependencies_plugin).execute_command("pip install '-rrequirements.txt'",
any_value(), shell=True)


class InstallBuildDependenciesTest(unittest.TestCase):
Expand All @@ -219,6 +234,7 @@ def tearDown(self):
def test_should_install_multiple_dependencies(self):
self.project.build_depends_on("spam")
self.project.build_depends_on("eggs")
self.project.build_depends_on_requirements("requirements-dev.txt")

install_build_dependencies(self.logger, self.project)

Expand All @@ -228,6 +244,9 @@ def test_should_install_multiple_dependencies(self):
verify(
pybuilder.plugins.python.install_dependencies_plugin).execute_command("pip install 'eggs'",
any_value(), shell=True)
verify(
pybuilder.plugins.python.install_dependencies_plugin).execute_command("pip install '-rrequirements-dev.txt'",
any_value(), shell=True)


class InstallDependenciesTest(unittest.TestCase):
Expand Down

0 comments on commit a745d97

Please sign in to comment.