Repository: pypa/virtualenv

Issue:
With Git bash, cannot create virtualenv with a nested path.
With *Git Bash*, virtualenv refuses to create a virtualenv with a nested directory (ex: `foo/bar`), reporting that `/` is a path seperator and shouldn't be in the destination path.

I have no idea why `/` is considered a path separator (usually `;` or `:`, depending on OS, right?)

- [X] Minimal reproducible example or detailed descriptions
- [X] OS and `pip list` output

Environment: Windows 10, with Git Bash, using Python 3.7.
```
$ py -3.7 -m pip list
Package            Version
------------------ -------
appdirs            1.4.3
distlib            0.3.0
filelock           3.0.12
importlib-metadata 1.5.0
pip                20.0.2
setuptools         45.2.0
six                1.14.0
virtualenv         20.0.2
zipp               2.2.0
```

Example:
```
$ py -3.7 -m virtualenv foo/bar
usage: virtualenv [--version] [--with-traceback] [-v | -q] [--discovery {builtin}] [-p py] [--creator {builtin,cpython3-win,venv}] [--seeder {app-data,pip}] [--no-seed] [--activators comma_separated_list] [--clear] [--system-site-packages]
                  [--symlinks | --copies] [--download | --no-download] [--extra-search-dir d [d ...]] [--pip version] [--setuptools version] [--wheel version] [--no-pip] [--no-setuptools] [--no-wheel] [--clear-app-data] [--symlink-app-data]

                  [--prompt prompt] [-h]
                  dest
virtualenv: error: argument dest: destination 'foo/bar' must not contain the path separator (/) as this would break the activation scripts
```

And FYI:
```
$ py -3.7
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.pathsep
';'
>>>
```


Discussion:
Does it work if you pass the windows path separator instead of the UNIX one you do in your example? I feel like the error message is bad, but seems you're trying to use Unix paths on windows.
Yes, it'll work:
```
$ py -3.7 -m virtualenv foo\\bar
created virtual environment CPython3Windows(dest=F:\rendezvous_local\foo\bar, clear=False, global=False) with seeder FromAppData pip=latest setuptools=latest wheel=latest app_data_dir=C:\Users\vphilippon\AppData\Local\pypa\virtualenv\seed-v1 via=copy
```

Although, "I didn't have issues before" ™️ , but also usually don't have issues doing so using Git Bash with other python application.
Ultra-simple example:
```
$ py -3.7
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> with open('my_dir/my_file.txt') as f:
...     print(f.readlines())
...
['Hello gaborbernat!\n']
```
I do understand that virtualenv is likely doing way more stuff with that path, with millions of ways for things to go haywire. Yet, that's a regression in virtualenv IMO.
I'll try to dig in to see if I can give more details on what happens internally, and if I can submit something.

If you don't make headway on this I'll look into it tomorrow why this fails, and if it would be possible to make it work 🤞if you can come up with a pr that would be epic though 👍
@gaborbernat Do you remember why you decided to explicitly dissalow `os.altsep` in the path?
https://github.com/pypa/virtualenv/blob/0e00194464a4eaa12ee6fd48c7a49338381fc88e/src/virtualenv/create/creator.py#L120
https://github.com/pypa/virtualenv/commit/524d95e782d810243cf9cd344a88711591c94efc

Did you hit some specific issues with it?
If I undertand correctly, it should be a valid path component.
https://docs.python.org/3.8/library/os.html#os.altsep

Resolving patch:
diff --git a/src/virtualenv/create/creator.py b/src/virtualenv/create/creator.py
--- a/src/virtualenv/create/creator.py
+++ b/src/virtualenv/create/creator.py
@@ -117,12 +117,11 @@ def non_write_able(dest, value):
                     encoding, "".join(refused.keys()), raw_value
                 )
             )
-        for char in (i for i in (os.pathsep, os.altsep) if i is not None):
-            if char in raw_value:
-                raise ArgumentTypeError(
-                    "destination {!r} must not contain the path separator ({}) as this would break "
-                    "the activation scripts".format(raw_value, char)
-                )
+        if os.pathsep in raw_value:
+            raise ArgumentTypeError(
+                "destination {!r} must not contain the path separator ({}) as this would break "
+                "the activation scripts".format(raw_value, os.pathsep)
+            )
 
         value = Path(raw_value)
         if value.exists() and value.is_file():


Test patch:
diff --git a/tests/unit/create/test_creator.py b/tests/unit/create/test_creator.py
--- a/tests/unit/create/test_creator.py
+++ b/tests/unit/create/test_creator.py
@@ -25,13 +25,12 @@
 CURRENT = PythonInfo.current_system()
 
 
-@pytest.mark.parametrize("sep", [i for i in (os.pathsep, os.altsep) if i is not None])
-def test_os_path_sep_not_allowed(tmp_path, capsys, sep):
-    target = "{}{}".format(str(tmp_path / "a"), "{}b".format(sep))
+def test_os_path_sep_not_allowed(tmp_path, capsys):
+    target = str(tmp_path / "a{}b".format(os.pathsep))
     err = _non_success_exit_code(capsys, target)
     msg = (
         "destination {!r} must not contain the path separator ({}) as this"
-        " would break the activation scripts".format(target, sep)
+        " would break the activation scripts".format(target, os.pathsep)
     )
     assert msg in err, err
 
@@ -301,6 +300,13 @@ def test_creator_input_passed_is_abs(tmp_path, monkeypatch):
     assert str(result) == str(tmp_path / "venv")
 
 
+@pytest.mark.skipif(os.altsep is None, reason="OS does not have an altsep")
+def test_creator_replaces_altsep_in_dest(tmp_path):
+    dest = str(tmp_path / "venv{}foobar")
+    result = Creator.validate_dest(dest.format(os.altsep))
+    assert str(result) == dest.format(os.sep)
+
+
 def test_create_long_path(current_fastest, tmp_path):
     if sys.platform == "darwin":
         max_shebang_length = 512