Repository: python-poetry/poetry

Issue:
Spawns a shell within the virtualenv
It would be nice to have a command `poetry shell` that acts like `pipenv shell`, instead of having to `source ~/.cache/pypoetry/…/bin/activate`.


Discussion:
`poetry run <your shell binary here>`?
Perfect! I didn't think to test that…
I'd like to see this reopened. It would be neat to have this as a convenient shortcut. After all, poetry already knows what my shell is, so why do I need to tell it again?
I reopen and let @sdispater decide what to do of this.
@NotAFile how does poetry already know what your shell is?
@bertjwregeer through the `SHELL` environment variable
@NotAFile which may or may not be set, and may or may not be set to the correct shell...
@bertjwregeer Sure. Alternatives would have to be found for Windows. It's probably worth looking at how similar projects handle this. For *NIX I don't see anything wrong with using $SHELL. It's set by your shell, and if your shell doesn't know what shell it is, perhaps you have bigger problems...

Even then, if someone has an extremely weird setup where SHELL is somehow not the shell, it's not like the trusty normal "run" command wouldn't still be there.

Resolving patch:
diff --git a/poetry/console/application.py b/poetry/console/application.py
--- a/poetry/console/application.py
+++ b/poetry/console/application.py
@@ -28,6 +28,7 @@
 from .commands import RunCommand
 from .commands import ScriptCommand
 from .commands import SearchCommand
+from .commands import ShellCommand
 from .commands import ShowCommand
 from .commands import UpdateCommand
 from .commands import VersionCommand
@@ -119,6 +120,7 @@ def get_default_commands(self):  # type: () -> list
             RunCommand(),
             ScriptCommand(),
             SearchCommand(),
+            ShellCommand(),
             ShowCommand(),
             UpdateCommand(),
             VersionCommand(),
diff --git a/poetry/console/commands/__init__.py b/poetry/console/commands/__init__.py
--- a/poetry/console/commands/__init__.py
+++ b/poetry/console/commands/__init__.py
@@ -13,6 +13,7 @@
 from .run import RunCommand
 from .script import ScriptCommand
 from .search import SearchCommand
+from .shell import ShellCommand
 from .show import ShowCommand
 from .update import UpdateCommand
 from .version import VersionCommand
diff --git a/poetry/console/commands/shell.py b/poetry/console/commands/shell.py
new file mode 100644
--- /dev/null
+++ b/poetry/console/commands/shell.py
@@ -0,0 +1,43 @@
+from os import environ
+from distutils.util import strtobool
+
+from .venv_command import VenvCommand
+
+
+class ShellCommand(VenvCommand):
+    """
+    Spawns a shell within the virtual environment.
+
+    shell [options]
+    """
+
+    help = """The <info>shell</> command spawns a shell, according to the
+<comment>$SHELL</> environment variable, within the virtual environment.
+If one doesn't exist yet, it will be created.
+"""
+
+    def handle(self):
+        from poetry.utils.shell import Shell
+
+        # Check if it's already activated or doesn't exist and won't be created
+        if strtobool(environ.get("POETRY_ACTIVE", "0")) or not self.venv.is_venv():
+            current_venv = environ.get("VIRTUAL_ENV")
+
+            if current_venv:
+                self.line(
+                    "Virtual environment already activated: "
+                    "<info>{}</>".format(current_venv)
+                )
+
+            else:
+                self.error("Virtual environment wasn't found")
+
+            return
+
+        self.line("Spawning shell within <info>{}</>".format(self.venv.venv))
+
+        # Setting this to avoid spawning unnecessary nested shells
+        environ["POETRY_ACTIVE"] = "1"
+        shell = Shell.get()
+        self.venv.execute(shell.path)
+        environ.pop("POETRY_ACTIVE")


Test patch: