Skip to content

Commit

Permalink
Add pipArgs configuration option for passing additional arguments t…
Browse files Browse the repository at this point in the history
…o pip (closes #76)
  • Loading branch information
logandk committed Dec 7, 2018
1 parent e26d894 commit 685adb9
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Features

- Add `pipArgs` configuration option for passing additional arguments to pip (#76)
- Add support for ALB requests (#77)

_Alan Trope_
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ custom:
packRequirements: false
```

In order to pass additional arguments to `pip` when installing requirements, the `pipArgs` configuration
option is available:

```yaml
custom:
wsgi:
app: api.app
pipArgs: --no-deps
```

For a more advanced approach to packaging requirements, consider using https://github.com/UnitedIncome/serverless-python-requirements.

### Python version
Expand Down
12 changes: 10 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ BbPromise.promisifyAll(fse);
class ServerlessWSGI {
validate() {
this.enableRequirements = true;
this.pipArgs = null;

if (this.serverless.service.custom && this.serverless.service.custom.wsgi) {
if (this.serverless.service.custom.wsgi.app) {
Expand All @@ -24,6 +25,8 @@ class ServerlessWSGI {
if (this.serverless.service.custom.wsgi.packRequirements === false) {
this.enableRequirements = false;
}

this.pipArgs = this.serverless.service.custom.wsgi.pipArgs;
}

if (this.enableRequirements) {
Expand Down Expand Up @@ -135,12 +138,17 @@ class ServerlessWSGI {
}

packRequirements() {
if (!this.enableRequirements) {
return BbPromise.resolve();
}

const requirementsPath = this.appPath || this.serverless.config.servicePath;
const requirementsFile = path.join(requirementsPath, "requirements.txt");
let args = [path.resolve(__dirname, "requirements.py")];

if (!this.enableRequirements) {
return BbPromise.resolve();
if (this.pipArgs) {
args.push("--pip-args");
args.push(this.pipArgs);
}

if (this.wsgiApp) {
Expand Down
42 changes: 42 additions & 0 deletions index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,48 @@ describe("serverless-wsgi", () => {
});
});

it("packages user requirements with additional pip args", () => {
var plugin = new Plugin(
{
config: { servicePath: "/tmp" },
service: {
provider: { runtime: "python3.6" },
custom: { wsgi: { pipArgs: "--no-deps 'imaginary \"value\"'" } }
},
classes: { Error: Error },
cli: { log: () => {} }
},
{}
);

var sandbox = sinon.createSandbox();
var hasbinStub = sandbox.stub(hasbin, "sync").returns(true);
var copyStub = sandbox.stub(fse, "copyAsync");
var writeStub = sandbox.stub(fse, "writeFileAsync");
sandbox.stub(fse, "symlinkSync").throws();
sandbox.stub(fse, "readlinkSync").returns("/tmp/.requirements/flask");
sandbox.stub(fse, "readdirSync").returns(["flask"]);
sandbox.stub(fse, "existsSync").returns(true);
var procStub = sandbox
.stub(child_process, "spawnSync")
.returns({ status: 0 });
plugin.hooks["before:package:createDeploymentArtifacts"]().then(() => {
expect(hasbinStub.calledWith("python3.6")).to.be.true;
expect(copyStub.called).to.be.false;
expect(writeStub.called).to.be.false;
expect(
procStub.calledWith("python3.6", [
path.resolve(__dirname, "requirements.py"),
"--pip-args",
"--no-deps 'imaginary \"value\"'",
"/tmp/requirements.txt",
"/tmp/.requirements"
])
).to.be.true;
sandbox.restore();
});
});

it("skips packaging for non-wsgi app without user requirements", () => {
var plugin = new Plugin(
{
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 18 additions & 5 deletions requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""
import os
import platform
import shlex
import shutil
import subprocess
import sys
Expand All @@ -20,7 +21,7 @@
sys.exit("Unable to load virtualenv, please install")


def package(req_files, target_dir):
def package(req_files, target_dir, pip_args=""):
venv_dir = os.path.join(target_dir, ".venv")
tmp_dir = os.path.join(target_dir, ".tmp")

Expand Down Expand Up @@ -68,7 +69,8 @@ def package(req_files, target_dir):

for req_file in req_files:
p = subprocess.Popen(
[pip_exe, "install", "-r", req_file], stdout=subprocess.PIPE
[pip_exe, "install", "-r", req_file] + shlex.split(pip_args),
stdout=subprocess.PIPE,
)
p.communicate()
if p.returncode != 0:
Expand Down Expand Up @@ -105,9 +107,20 @@ def package(req_files, target_dir):


if __name__ == "__main__": # pragma: no cover
if len(sys.argv) < 3:
args = sys.argv
pip_args = ""

if len(args) > 3 and args[1] == "--pip-args":
pip_args = args[2]
args = args[3:]
else:
args = args[1:]

if len(args) < 2:
sys.exit(
"Usage: {} REQ_FILE... TARGET_DIR".format(os.path.basename(sys.argv[0]))
"Usage: {} --pip-args '--no-deps' REQ_FILE... TARGET_DIR".format(
os.path.basename(sys.argv[0])
)
)

package(sys.argv[1:-1], sys.argv[-1])
package(args[:-1], args[-1], pip_args)
25 changes: 24 additions & 1 deletion requirements_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@


class PopenStub:

def __init__(self, returncode):
self.returncode = returncode

Expand Down Expand Up @@ -168,3 +167,27 @@ def test_pip_error(mock_system, mock_virtualenv, monkeypatch):

with pytest.raises(SystemExit):
requirements.package(["/path1/requirements.txt"], "/tmp")


def test_package_with_pip_args(mock_system, mock_virtualenv):
requirements.package(
["/path1/requirements.txt"],
"/tmp",
"--no-deps --imaginary-arg 'imaginary \"value\"'",
)

# Invokes pip for package installation
assert mock_system[14] == (
"subprocess.Popen",
(
[
"/tmp/.venv/bin/pip",
"install",
"-r",
"/path1/requirements.txt",
"--no-deps",
"--imaginary-arg",
'imaginary "value"',
],
),
)

0 comments on commit 685adb9

Please sign in to comment.