Skip to content

Commit 0cf5008

Browse files
authored
fix(python): bin script python support, test argument passing (#3762)
Corrects multiple issues with running `bin` scripts from python. These were discovered in the context of this `projen` issue: projen/projen#2103 - Corrects broken argument marshaling to binary scripts introduced in #3694 - Exposes exit code and stderr from script execution instead of failing silently Additionally, adds more robust test coverage of passing arguments to `bin` scripts. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
1 parent 72f2e7c commit 0cf5008

File tree

8 files changed

+108
-22
lines changed

8 files changed

+108
-22
lines changed

.all-contributorsrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,15 @@
14661466
"contributions": [
14671467
"bug"
14681468
]
1469+
},
1470+
{
1471+
"login": "jmalins",
1472+
"name": "Jeff Malins",
1473+
"avatar_url": "https://avatars.githubusercontent.com/u/2001356?v=4",
1474+
"profile": "https://github.com/jmalins",
1475+
"contributions": [
1476+
"code"
1477+
]
14691478
}
14701479
],
14711480
"repoType": "github",

README.md

Lines changed: 13 additions & 12 deletions
Large diffs are not rendered by default.

packages/@jsii/kernel/src/kernel.test.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,10 +2144,27 @@ defineTest('invokeBinScript() return output', (sandbox) => {
21442144
script: 'calc',
21452145
});
21462146

2147-
expect(result.stdout).toEqual('Hello World!\n');
2148-
expect(result.stderr).toEqual('');
2149-
expect(result.status).toEqual(0);
2150-
expect(result.signal).toBeNull();
2147+
expect(result).toMatchObject<api.InvokeScriptResponse>({
2148+
status: 0,
2149+
stdout: 'Hello World!\n',
2150+
stderr: '',
2151+
signal: null,
2152+
});
2153+
});
2154+
2155+
defineTest('invokeBinScript() accepts arguments', (sandbox) => {
2156+
const result = sandbox.invokeBinScript({
2157+
assembly: 'jsii-calc',
2158+
script: 'calc',
2159+
args: ['arg1', 'arg2'],
2160+
});
2161+
2162+
expect(result).toMatchObject<api.InvokeScriptResponse>({
2163+
status: 0,
2164+
stdout: 'Hello World!\n arguments: arg1, arg2\n',
2165+
stderr: '',
2166+
signal: null,
2167+
});
21512168
});
21522169

21532170
// =================================================================================================

packages/@jsii/python-runtime/src/jsii/_runtime.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import abc
22
import os
3+
import sys
34

45
import attr
56

6-
from typing import cast, Any, Callable, List, Optional, Mapping, Type, TypeVar
7+
from typing import Sequence, cast, Any, Callable, List, Optional, Mapping, Type, TypeVar
78

89
from . import _reference_map
910
from ._compat import importlib_resources
@@ -47,10 +48,23 @@ def load(cls, *args, _kernel=kernel, **kwargs) -> "JSIIAssembly":
4748

4849
@classmethod
4950
def invokeBinScript(
50-
cls, pkgname: str, script: str, *args: str, _kernel=kernel
51-
) -> None:
51+
cls,
52+
pkgname: str,
53+
script: str,
54+
args: Optional[Sequence[str]] = None,
55+
_kernel=kernel,
56+
) -> int:
57+
if args is None:
58+
args = []
59+
5260
response = _kernel.invokeBinScript(pkgname, script, args)
53-
print(response.stdout)
61+
if response.stdout:
62+
print(response.stdout)
63+
64+
if response.stderr:
65+
print(response.stderr, file=sys.stderr)
66+
67+
return response.status
5468

5569

5670
class JSIIMeta(_ClassPropertyMeta, type):
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import platform
2+
import subprocess
3+
import sys
4+
import pytest
5+
6+
7+
class TestInvokeBinScript:
8+
@pytest.mark.skipif(
9+
platform.system() == "Windows",
10+
reason="jsii-pacmak does not generate windows scripts",
11+
)
12+
def test_invoke_script(self) -> None:
13+
result = run_script("calc")
14+
15+
assert result.returncode == 0
16+
assert result.stdout == b"Hello World!\n\n"
17+
assert result.stderr == b""
18+
19+
@pytest.mark.skipif(
20+
platform.system() == "Windows",
21+
reason="jsii-pacmak does not generate windows scripts",
22+
)
23+
def test_invoke_script_with_args(self) -> None:
24+
result = run_script("calc", "arg1", "arg2")
25+
26+
assert result.returncode == 0
27+
assert result.stdout == b"Hello World!\n arguments: arg1, arg2\n\n"
28+
assert result.stderr == b""
29+
30+
31+
def run_script(script_name: str, *args: str) -> subprocess.CompletedProcess:
32+
if platform.system() == "Windows":
33+
# currently not used, the calling semantics have not been defined for bin scripts on windows
34+
script_path = f".env\\Scripts\\{script_name}"
35+
return subprocess.run([sys.executable, script_path, *args], capture_output=True)
36+
else:
37+
script_path = f".env/bin/{script_name}"
38+
return subprocess.run([script_path, *args], capture_output=True)

packages/jsii-calc/bin/run.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@
33
/* eslint-disable no-console */
44

55
console.info('Hello World!');
6+
7+
const args = process.argv.slice(2);
8+
if (args.length > 0) {
9+
console.info(` arguments: ${args.join(', ')}`);
10+
}

packages/jsii-pacmak/lib/targets/python.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1792,14 +1792,15 @@ class PythonModule implements PythonType {
17921792
code.line();
17931793
emitList(
17941794
code,
1795-
'__jsii_assembly__.invokeBinScript(',
1795+
'exit_code = __jsii_assembly__.invokeBinScript(',
17961796
[
17971797
JSON.stringify(this.assembly.name),
17981798
JSON.stringify(name),
17991799
'sys.argv[1:]',
18001800
],
18011801
')',
18021802
);
1803+
code.line('exit(exit_code)');
18031804
code.closeFile(script_file);
18041805
scripts.push(script_file.replace(/\\/g, '/'));
18051806
}

packages/jsii-pacmak/test/generated-code/__snapshots__/target-python.test.js.snap

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)