diff --git a/aws_lambda_builders/workflows/python_pip/packager.py b/aws_lambda_builders/workflows/python_pip/packager.py index c427a958b..34058602b 100644 --- a/aws_lambda_builders/workflows/python_pip/packager.py +++ b/aws_lambda_builders/workflows/python_pip/packager.py @@ -35,6 +35,11 @@ class InvalidSourceDistributionNameError(PackagerError): class RequirementsFileNotFoundError(PackagerError): + """ + Exceptions is no longer raised. + Keeping it here because this exception is 'public' and could still be used by a customer. + """ + def __init__(self, requirements_path): super(RequirementsFileNotFoundError, self).__init__("Requirements file not found: %s" % requirements_path) @@ -131,9 +136,6 @@ def build_dependencies(self, artifacts_dir_path, scratch_dir_path, requirements_ # by finding/creating a virtualenv of the correct version and when # pip is called set the appropriate env vars. - if not self.osutils.file_exists(requirements_path): - raise RequirementsFileNotFoundError(requirements_path) - self._dependency_builder.build_site_packages(requirements_path, artifacts_dir_path, scratch_dir_path) diff --git a/aws_lambda_builders/workflows/python_pip/workflow.py b/aws_lambda_builders/workflows/python_pip/workflow.py index 2ed5c0976..c682df8cf 100644 --- a/aws_lambda_builders/workflows/python_pip/workflow.py +++ b/aws_lambda_builders/workflows/python_pip/workflow.py @@ -1,11 +1,16 @@ """ Python PIP Workflow """ +import logging + from aws_lambda_builders.workflow import BaseWorkflow, Capability from aws_lambda_builders.actions import CopySourceAction from aws_lambda_builders.workflows.python_pip.validator import PythonRuntimeValidator from .actions import PythonPipBuildAction +from .utils import OSUtils + +LOG = logging.getLogger(__name__) class PythonPipWorkflow(BaseWorkflow): @@ -59,16 +64,26 @@ class PythonPipWorkflow(BaseWorkflow): ".idea", ) - def __init__(self, source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=None, **kwargs): + def __init__(self, source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=None, osutils=None, **kwargs): super(PythonPipWorkflow, self).__init__( source_dir, artifacts_dir, scratch_dir, manifest_path, runtime=runtime, **kwargs ) - self.actions = [ - PythonPipBuildAction(artifacts_dir, scratch_dir, manifest_path, runtime, binaries=self.binaries), - CopySourceAction(source_dir, artifacts_dir, excludes=self.EXCLUDED_FILES), - ] + if osutils is None: + osutils = OSUtils() + + if osutils.file_exists(manifest_path): + # If a requirements.txt exists, run pip builder before copy action. + self.actions = [ + PythonPipBuildAction(artifacts_dir, scratch_dir, manifest_path, runtime, binaries=self.binaries), + CopySourceAction(source_dir, artifacts_dir, excludes=self.EXCLUDED_FILES), + ] + else: + LOG.warning("requirements.txt file not found. Continuing the build without dependencies.") + self.actions = [ + CopySourceAction(source_dir, artifacts_dir, excludes=self.EXCLUDED_FILES), + ] def get_validators(self): return [PythonRuntimeValidator(runtime=self.runtime)] diff --git a/tests/integration/workflows/python_pip/test_python_pip.py b/tests/integration/workflows/python_pip/test_python_pip.py index 745e560d7..265b4513f 100644 --- a/tests/integration/workflows/python_pip/test_python_pip.py +++ b/tests/integration/workflows/python_pip/test_python_pip.py @@ -3,9 +3,13 @@ import sys import tempfile from unittest import TestCase +import mock from aws_lambda_builders.builder import LambdaBuilder from aws_lambda_builders.exceptions import WorkflowFailedError +import logging + +logger = logging.getLogger("aws_lambda_builders.workflows.python_pip.workflow") class TestPythonPipWorkflow(TestCase): @@ -88,9 +92,8 @@ def test_must_fail_to_resolve_dependencies(self): ) or "Invalid requirement: u'adfasf=1.2.3'" in str(ctx.exception) self.assertTrue(message_in_exception) - def test_must_fail_if_requirements_not_found(self): - - with self.assertRaises(WorkflowFailedError) as ctx: + def test_must_log_warning_if_requirements_not_found(self): + with mock.patch.object(logger, "warning") as mock_warning: self.builder.build( self.source_dir, self.artifacts_dir, @@ -98,13 +101,9 @@ def test_must_fail_if_requirements_not_found(self): os.path.join("non", "existent", "manifest"), runtime=self.runtime, ) - - self.builder.build( - self.source_dir, - self.artifacts_dir, - self.scratch_dir, - os.path.join("non", "existent", "manifest"), - runtime=self.runtime, - ) - - self.assertIn("Requirements file not found", str(ctx.exception)) + expected_files = self.test_data_files + output_files = set(os.listdir(self.artifacts_dir)) + self.assertEqual(expected_files, output_files) + mock_warning.assert_called_once_with( + "requirements.txt file not found. Continuing the build without dependencies." + ) diff --git a/tests/unit/workflows/python_pip/test_packager.py b/tests/unit/workflows/python_pip/test_packager.py index 032d0b95f..af3a4c270 100644 --- a/tests/unit/workflows/python_pip/test_packager.py +++ b/tests/unit/workflows/python_pip/test_packager.py @@ -113,7 +113,6 @@ def test_can_call_dependency_builder(self, osutils): mock_dep_builder.build_site_packages.assert_called_once_with( "path/to/requirements.txt", "artifacts/path/", "scratch_dir/path/" ) - osutils_mock.file_exists.assert_called_once_with("path/to/requirements.txt") class TestPackage(object): diff --git a/tests/unit/workflows/python_pip/test_workflow.py b/tests/unit/workflows/python_pip/test_workflow.py index b4adbc925..01e960543 100644 --- a/tests/unit/workflows/python_pip/test_workflow.py +++ b/tests/unit/workflows/python_pip/test_workflow.py @@ -1,19 +1,37 @@ +import mock + from unittest import TestCase from aws_lambda_builders.actions import CopySourceAction +from aws_lambda_builders.workflows.python_pip.utils import OSUtils from aws_lambda_builders.workflows.python_pip.validator import PythonRuntimeValidator from aws_lambda_builders.workflows.python_pip.workflow import PythonPipBuildAction, PythonPipWorkflow class TestPythonPipWorkflow(TestCase): def setUp(self): - self.workflow = PythonPipWorkflow("source", "artifacts", "scratch_dir", "manifest", runtime="python3.7") + self.osutils = OSUtils() def test_workflow_sets_up_actions(self): + osutils_mock = mock.Mock(spec=self.osutils) + osutils_mock.file_exists.return_value = True + self.workflow = PythonPipWorkflow( + "source", "artifacts", "scratch_dir", "manifest", runtime="python3.7", osutils=osutils_mock + ) self.assertEqual(len(self.workflow.actions), 2) self.assertIsInstance(self.workflow.actions[0], PythonPipBuildAction) self.assertIsInstance(self.workflow.actions[1], CopySourceAction) + def test_workflow_sets_up_actions_without_requirements(self): + osutils_mock = mock.Mock(spec=self.osutils) + osutils_mock.file_exists.return_value = False + self.workflow = PythonPipWorkflow( + "source", "artifacts", "scratch_dir", "manifest", runtime="python3.7", osutils=osutils_mock + ) + self.assertEqual(len(self.workflow.actions), 1) + self.assertIsInstance(self.workflow.actions[0], CopySourceAction) + def test_workflow_validator(self): + self.workflow = PythonPipWorkflow("source", "artifacts", "scratch_dir", "manifest", runtime="python3.7") for validator in self.workflow.get_validators(): self.assertTrue(isinstance(validator, PythonRuntimeValidator))