Repository: aws-cloudformation/cloudformation-cli-python-plugin

Issue:
It looks like the upgrade to 2.1.6 has broken dependency installation in `cfn submit --dry-run`
The pip installation in `cfn submit` appears to log pip usage instructions to stdout instead of actually installing the depenencies.

If we downgrade to 2.1.5 then the dependencies are included in the build dir.

If we run 2.1.6, then the build directory does not contain any of the pip dependencies that we'd expect.

This is consistent if I downgrade and then re-upgrade, but I don't have a public project i can share to demonstrate the behaviour.

Example .rpdk-config:


```{
    "artifact_type": "HOOK",
    "typeName": "XXX::XXX::XXX",
    "language": "python37",
    "runtime": "python3.7",
    "entrypoint": "xxx.handlers.hook",
    "testEntrypoint": "xxx.handlers.hook",
    "settings": {
        "version": false,
        "subparser_name": null,
        "verbose": 0,
        "force": false,
        "type_name": null,
        "artifact_type": null,
        "endpoint_url": null,
        "region": null,
        "target_schemas": [],
        "use_docker": false,
        "protocolVersion": "2.0.0"
    }
}
```


Discussion:

Patch:
diff --git a/README.md b/README.md
index cd5ec66..6854fe5 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,14 @@ This plugin library helps to provide runtime bindings for the execution of your
 
 [![Build Status](https://travis-ci.com/aws-cloudformation/cloudformation-cli-python-plugin.svg?branch=master)](https://travis-ci.com/aws-cloudformation/cloudformation-cli-python-plugin)
 
+## Community
+
+Join us on Discord! Connect & interact with CloudFormation developers &
+experts, find channels to discuss and get help for our CLIs, cfn-lint, CloudFormation registry, StackSets,
+Guard and more:
+
+[![Join our Discord](https://discordapp.com/api/guilds/981586120448020580/widget.png?style=banner3)](https://discord.gg/9zpd7TTRwq)
+
 Installation
 ------------
 
diff --git a/python/rpdk/python/codegen.py b/python/rpdk/python/codegen.py
index f5c49cf..60174aa 100644
--- a/python/rpdk/python/codegen.py
+++ b/python/rpdk/python/codegen.py
@@ -334,14 +334,24 @@ class Python36LanguagePlugin(LanguagePlugin):
 
         LOG.warning("Starting pip build.")
         try:
-            completed_proc = subprocess_run(  # nosec
-                command,
-                stdout=PIPE,
-                stderr=PIPE,
-                cwd=base_path,
-                check=True,
-                shell=True,
-            )
+            # On windows run pip command through the default shell (CMD)
+            if os.name == "nt":
+                completed_proc = subprocess_run(  # nosec
+                    command,
+                    stdout=PIPE,
+                    stderr=PIPE,
+                    cwd=base_path,
+                    check=True,
+                    shell=True,
+                )
+            else:
+                completed_proc = subprocess_run(  # nosec
+                    command,
+                    stdout=PIPE,
+                    stderr=PIPE,
+                    cwd=base_path,
+                    check=True,
+                )
             LOG.warning("pip build finished.")
         except (FileNotFoundError, CalledProcessError) as e:
             raise DownstreamError("pip build failed") from e


Test patch:
diff --git a/tests/plugin/codegen_test.py b/tests/plugin/codegen_test.py
index a36d04b..aa64261 100644
--- a/tests/plugin/codegen_test.py
+++ b/tests/plugin/codegen_test.py
@@ -416,6 +416,43 @@ def test__build_pip(plugin):
     mock_pip.assert_called_once_with(sentinel.base_path)
 
 
+def test__build_pip_posix(plugin):
+    patch_os_name = patch("rpdk.python.codegen.os.name", "posix")
+    patch_subproc = patch("rpdk.python.codegen.subprocess_run")
+
+    # Path must be set outside simulated os.name
+    temppath = Path(str(sentinel.base_path))
+    with patch_os_name, patch_subproc as mock_subproc:
+        plugin._pip_build(temppath)
+
+    mock_subproc.assert_called_once_with(
+        plugin._make_pip_command(temppath),
+        stdout=ANY,
+        stderr=ANY,
+        cwd=temppath,
+        check=ANY,
+    )
+
+
+def test__build_pip_windows(plugin):
+    patch_os_name = patch("rpdk.python.codegen.os.name", "nt")
+    patch_subproc = patch("rpdk.python.codegen.subprocess_run")
+
+    # Path must be set outside simulated os.name
+    temppath = Path(str(sentinel.base_path))
+    with patch_os_name, patch_subproc as mock_subproc:
+        plugin._pip_build(temppath)
+
+    mock_subproc.assert_called_once_with(
+        plugin._make_pip_command(temppath),
+        stdout=ANY,
+        stderr=ANY,
+        cwd=temppath,
+        check=ANY,
+        shell=True,
+    )
+
+
 def test__build_docker(plugin):
     plugin._use_docker = True