vexx 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
vexx-0.1.0/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Sasha Hart
2
+ Copyright (c) 2026 Adam Henderson
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
vexx-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: vexx
3
+ Version: 0.1.0
4
+ Summary: Run commands in a virtualenv
5
+ Project-URL: Homepage, https://github.com/a-hendo/vex
6
+ Project-URL: Repository, https://github.com/a-hendo/vex
7
+ Author-email: Adam Henderson <adamhenderson90@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: deployment,installation,virtualenv,virtualenvwrapper,workon
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: Microsoft :: Windows
17
+ Classifier: Operating System :: POSIX
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development
22
+ Classifier: Topic :: System :: Shells
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.12
25
+ Requires-Dist: virtualenv
26
+ Description-Content-Type: text/markdown
27
+
28
+ # Vex
29
+
30
+ **Run a command in a virtualenv.**
31
+
32
+ Vex is an elegant, shell-agnostic tool for running commands inside virtual environments. Unlike traditional methods that rely on "activating" and "deactivating" environments by mutating your current shell's state, Vex simply launches a new process with the correct environment variables (like `PATH` and `VIRTUAL_ENV`) already set.
33
+
34
+ When the command finishes, the environment is gone. No cleanup, no `deactivate`, no shell-specific hacks.
35
+
36
+ ## Modernization
37
+
38
+ Vex has been modernized to support the latest Python standards:
39
+
40
+ - **Python 3.12+ Required**: Leveraging modern features and built-in type safety.
41
+ - **UV Integration**: Vex now detects and uses [uv](https://github.com/astral-sh/uv) for lightning-fast virtualenv creation when using `--make`.
42
+ - **Pyproject.toml**: Fully migrated to modern PEP 517/518 packaging.
43
+ - **Type Safety**: The entire codebase is now fully type-hinted.
44
+
45
+ ## How it works
46
+
47
+ `vex` runs any command in a virtualenv without modifying your current shell.
48
+
49
+ The standard way to use a virtualenv involves sourcing an `activate` script which modifies your shell's environment and adds a `deactivate` function. This is often brittle and shell-specific.
50
+
51
+ Vex takes a simpler approach: it calculates the environment required for the virtualenv and passes it directly to a new subprocess. This makes it naturally compatible with **bash, zsh, fish, PowerShell, cmd.exe**, and any other shell or executable.
52
+
53
+ ## Examples
54
+
55
+ - `vex myenv bash`: Launch a bash shell with virtualenv `myenv` enabled. Exit the shell (Ctrl-D) to "deactivate".
56
+ - `vex myenv python`: Launch a Python interpreter inside virtualenv `myenv`.
57
+ - `vex myenv pip install requests`: Install a package into `myenv` without activating it.
58
+ - `vex -m ephemeral echo "Hello"`: Create a new virtualenv named `ephemeral`, run the command, and then immediately **remove** the virtualenv.
59
+ - `vex --path ./venv python script.py`: Run a script using a virtualenv located at a specific path.
60
+
61
+ ## Installation
62
+
63
+ The recommended way to install Vex is using [uv](https://github.com/astral-sh/uv):
64
+
65
+ ```bash
66
+ uv tool install vexx
67
+ ```
68
+
69
+ Alternatively, you can use pip:
70
+
71
+ ```bash
72
+ pip install --user vexx
73
+ ```
74
+
75
+ ### Usage with UV
76
+
77
+ Vex is designed to work seamlessly with `uv`. If `uv` is installed on your system, `vex --make` will automatically use `uv venv` to create environments, which is significantly faster than traditional `virtualenv`.
78
+
79
+ ## Config
80
+
81
+ Vex looks for an optional configuration file at `~/.vexrc`.
82
+
83
+ ```ini
84
+ shell=bash
85
+ virtualenvs=~/.virtualenvs
86
+ python=python3.12
87
+ env:
88
+ ANSWER=42
89
+ ```
90
+
91
+ - **shell**: The default shell to run if no command is provided (e.g., `vex myenv`).
92
+ - **virtualenvs**: The directory where your named virtualenvs are stored (defaults to `$WORKON_HOME` or `~/.virtualenvs`).
93
+ - **python**: The default Python executable to use when creating new environments with `--make`.
94
+ - **env**: Custom environment variables to inject into every Vex-managed process.
95
+
96
+ ## Environment Variables
97
+
98
+ ### WORKON_HOME
99
+
100
+ Vex uses the `WORKON_HOME` environment variable to determine where named virtual environments are stored. By default, this is `~/.virtualenvs`.
101
+
102
+ If you are using **uv** in a project and want Vex to target virtual environments local to your current directory (like a `.venv` folder), it is recommended to set `WORKON_HOME` to `./`:
103
+
104
+ ```bash
105
+ export WORKON_HOME="./"
106
+ ```
107
+
108
+ This allows you to use `vex .venv python` to run commands in your local project environment seamlessly.
109
+
110
+ ## Shell Prompts
111
+
112
+ Vex does not automatically change your prompt. To see the current virtualenv in your prompt, you can use the `$VIRTUAL_ENV` variable in your shell configuration.
113
+
114
+ **Bash Example (~/.bashrc):**
115
+
116
+ ```bash
117
+ function virtualenv_prompt() {
118
+ if [ -n "$VIRTUAL_ENV" ]; then
119
+ echo "(${VIRTUAL_ENV##*/}) "
120
+ fi
121
+ }
122
+ export PS1='$(virtualenv_prompt)\u@\H> '
123
+ ```
124
+
125
+ ## Shell Completion
126
+
127
+ Vex provides completion for virtualenv names. To enable it, add the following to your shell config:
128
+
129
+ **Bash (~/.bashrc):**
130
+ `eval "$(vex --shell-config bash)"`
131
+
132
+ **Zsh (~/.zshrc):**
133
+ `eval "$(vex --shell-config zsh)"`
134
+
135
+ **Fish (~/.config/fish/config.fish):**
136
+ `vex --shell-config fish | source`
137
+
138
+ ## Development
139
+
140
+ Vex development is now managed with `uv`.
141
+
142
+ ```bash
143
+ git clone https://github.com/a-hendo/vex
144
+ cd vex
145
+ uv sync
146
+ uv run pytest
147
+ ```
148
+
149
+ ## Credits
150
+
151
+ Vex was originally created by [Sasha Hart](https://github.com/sashahart). This version is a modernized fork of the [original project](https://github.com/sashahart/vex).
vexx-0.1.0/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Vex
2
+
3
+ **Run a command in a virtualenv.**
4
+
5
+ Vex is an elegant, shell-agnostic tool for running commands inside virtual environments. Unlike traditional methods that rely on "activating" and "deactivating" environments by mutating your current shell's state, Vex simply launches a new process with the correct environment variables (like `PATH` and `VIRTUAL_ENV`) already set.
6
+
7
+ When the command finishes, the environment is gone. No cleanup, no `deactivate`, no shell-specific hacks.
8
+
9
+ ## Modernization
10
+
11
+ Vex has been modernized to support the latest Python standards:
12
+
13
+ - **Python 3.12+ Required**: Leveraging modern features and built-in type safety.
14
+ - **UV Integration**: Vex now detects and uses [uv](https://github.com/astral-sh/uv) for lightning-fast virtualenv creation when using `--make`.
15
+ - **Pyproject.toml**: Fully migrated to modern PEP 517/518 packaging.
16
+ - **Type Safety**: The entire codebase is now fully type-hinted.
17
+
18
+ ## How it works
19
+
20
+ `vex` runs any command in a virtualenv without modifying your current shell.
21
+
22
+ The standard way to use a virtualenv involves sourcing an `activate` script which modifies your shell's environment and adds a `deactivate` function. This is often brittle and shell-specific.
23
+
24
+ Vex takes a simpler approach: it calculates the environment required for the virtualenv and passes it directly to a new subprocess. This makes it naturally compatible with **bash, zsh, fish, PowerShell, cmd.exe**, and any other shell or executable.
25
+
26
+ ## Examples
27
+
28
+ - `vex myenv bash`: Launch a bash shell with virtualenv `myenv` enabled. Exit the shell (Ctrl-D) to "deactivate".
29
+ - `vex myenv python`: Launch a Python interpreter inside virtualenv `myenv`.
30
+ - `vex myenv pip install requests`: Install a package into `myenv` without activating it.
31
+ - `vex -m ephemeral echo "Hello"`: Create a new virtualenv named `ephemeral`, run the command, and then immediately **remove** the virtualenv.
32
+ - `vex --path ./venv python script.py`: Run a script using a virtualenv located at a specific path.
33
+
34
+ ## Installation
35
+
36
+ The recommended way to install Vex is using [uv](https://github.com/astral-sh/uv):
37
+
38
+ ```bash
39
+ uv tool install vexx
40
+ ```
41
+
42
+ Alternatively, you can use pip:
43
+
44
+ ```bash
45
+ pip install --user vexx
46
+ ```
47
+
48
+ ### Usage with UV
49
+
50
+ Vex is designed to work seamlessly with `uv`. If `uv` is installed on your system, `vex --make` will automatically use `uv venv` to create environments, which is significantly faster than traditional `virtualenv`.
51
+
52
+ ## Config
53
+
54
+ Vex looks for an optional configuration file at `~/.vexrc`.
55
+
56
+ ```ini
57
+ shell=bash
58
+ virtualenvs=~/.virtualenvs
59
+ python=python3.12
60
+ env:
61
+ ANSWER=42
62
+ ```
63
+
64
+ - **shell**: The default shell to run if no command is provided (e.g., `vex myenv`).
65
+ - **virtualenvs**: The directory where your named virtualenvs are stored (defaults to `$WORKON_HOME` or `~/.virtualenvs`).
66
+ - **python**: The default Python executable to use when creating new environments with `--make`.
67
+ - **env**: Custom environment variables to inject into every Vex-managed process.
68
+
69
+ ## Environment Variables
70
+
71
+ ### WORKON_HOME
72
+
73
+ Vex uses the `WORKON_HOME` environment variable to determine where named virtual environments are stored. By default, this is `~/.virtualenvs`.
74
+
75
+ If you are using **uv** in a project and want Vex to target virtual environments local to your current directory (like a `.venv` folder), it is recommended to set `WORKON_HOME` to `./`:
76
+
77
+ ```bash
78
+ export WORKON_HOME="./"
79
+ ```
80
+
81
+ This allows you to use `vex .venv python` to run commands in your local project environment seamlessly.
82
+
83
+ ## Shell Prompts
84
+
85
+ Vex does not automatically change your prompt. To see the current virtualenv in your prompt, you can use the `$VIRTUAL_ENV` variable in your shell configuration.
86
+
87
+ **Bash Example (~/.bashrc):**
88
+
89
+ ```bash
90
+ function virtualenv_prompt() {
91
+ if [ -n "$VIRTUAL_ENV" ]; then
92
+ echo "(${VIRTUAL_ENV##*/}) "
93
+ fi
94
+ }
95
+ export PS1='$(virtualenv_prompt)\u@\H> '
96
+ ```
97
+
98
+ ## Shell Completion
99
+
100
+ Vex provides completion for virtualenv names. To enable it, add the following to your shell config:
101
+
102
+ **Bash (~/.bashrc):**
103
+ `eval "$(vex --shell-config bash)"`
104
+
105
+ **Zsh (~/.zshrc):**
106
+ `eval "$(vex --shell-config zsh)"`
107
+
108
+ **Fish (~/.config/fish/config.fish):**
109
+ `vex --shell-config fish | source`
110
+
111
+ ## Development
112
+
113
+ Vex development is now managed with `uv`.
114
+
115
+ ```bash
116
+ git clone https://github.com/a-hendo/vex
117
+ cd vex
118
+ uv sync
119
+ uv run pytest
120
+ ```
121
+
122
+ ## Credits
123
+
124
+ Vex was originally created by [Sasha Hart](https://github.com/sashahart). This version is a modernized fork of the [original project](https://github.com/sashahart/vex).
@@ -0,0 +1,93 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "vexx"
7
+ dynamic = ["version"]
8
+ description = "Run commands in a virtualenv"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ keywords = ["virtualenv", "virtualenvwrapper", "workon", "installation", "deployment"]
13
+ authors = [
14
+ { name = "Adam Henderson", email = "adamhenderson90@gmail.com" },
15
+ ]
16
+ classifiers = [
17
+ "Topic :: Utilities",
18
+ "Topic :: Software Development",
19
+ "Topic :: System :: Shells",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: System Administrators",
22
+ "Environment :: Console",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Development Status :: 3 - Alpha",
25
+ "Operating System :: POSIX",
26
+ "Operating System :: POSIX :: Linux",
27
+ "Operating System :: Microsoft :: Windows",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ ]
31
+ dependencies = [
32
+ "virtualenv",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/a-hendo/vex"
37
+ Repository = "https://github.com/a-hendo/vex"
38
+
39
+ [project.scripts]
40
+ vex = "vex.main:main"
41
+
42
+ [tool.hatch.version]
43
+ path = "vex/_version.py"
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["vex"]
47
+
48
+ [tool.hatch.build.targets.sdist]
49
+ include = [
50
+ "/vex",
51
+ "/LICENSE",
52
+ "/README.md",
53
+ ]
54
+
55
+ [dependency-groups]
56
+ dev = [
57
+ "pytest",
58
+ "mypy",
59
+ "ruff",
60
+ "tox",
61
+ ]
62
+
63
+ [tool.ruff]
64
+ line-length = 88
65
+ target-version = "py312"
66
+
67
+ [tool.ruff.lint]
68
+ select = ["E", "F", "I", "UP", "B"]
69
+ ignore = []
70
+
71
+ [tool.mypy]
72
+ python_version = "3.12"
73
+ strict = true
74
+ warn_return_any = true
75
+ warn_unused_configs = true
76
+ disallow_untyped_defs = true
77
+
78
+ [tool.pytest.ini_options]
79
+ testpaths = ["vex/tests", "vex/functional_tests"]
80
+
81
+ [tool.tox]
82
+ legacy_tox_ini = """
83
+ [tox]
84
+ envlist = py312, py313
85
+ isolated_build = True
86
+
87
+ [testenv]
88
+ description = run tests
89
+ deps =
90
+ pytest
91
+ commands =
92
+ pytest {posargs:vex/tests vex/functional_tests}
93
+ """
@@ -0,0 +1,5 @@
1
+ """This module makes "vex" a package."""
2
+
3
+ from ._version import VERSION as __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1 @@
1
+ VERSION = "0.1.0"
@@ -0,0 +1,165 @@
1
+ """Config file processing (.vexrc)."""
2
+
3
+ import os
4
+ import platform
5
+ import re
6
+ import shlex
7
+ from collections import OrderedDict
8
+ from collections.abc import Generator
9
+ from pathlib import Path
10
+ from typing import Any
11
+ from re import Pattern
12
+
13
+ _IDENTIFIER_PATTERN: str = "[a-zA-Z][_a-zA-Z0-9]*"
14
+ _SQUOTE_RE: Pattern[str] = re.compile(r"'([^']*)'\Z") # NO squotes inside
15
+ _DQUOTE_RE: Pattern[str] = re.compile(r'"([^"]*)"\Z') # NO dquotes inside
16
+ _HEADING_RE: Pattern[str] = re.compile(rf"^({_IDENTIFIER_PATTERN}):[ \t\n\r]*\Z")
17
+ _VAR_RE: Pattern[str] = re.compile(
18
+ rf"[ \t]*({_IDENTIFIER_PATTERN}) *= *(.*)[ \t\n\r]*$"
19
+ )
20
+
21
+
22
+ class InvalidConfigError(Exception):
23
+ """Raised when there is an error during a .vexrc file parse."""
24
+
25
+ def __init__(self, filename: str, errors: list[tuple[int, str]]):
26
+ super().__init__()
27
+ self.filename = filename
28
+ self.errors = errors
29
+
30
+ def __str__(self) -> str:
31
+ return f"errors in {self.filename!r}, lines {[tup[0] for tup in self.errors]!r}"
32
+
33
+
34
+ class Vexrc:
35
+ """Parsed representation of a .vexrc config file."""
36
+
37
+ default_heading: str = "root"
38
+ default_encoding: str = "utf-8"
39
+
40
+ def __init__(self) -> None:
41
+ self.encoding: str = self.default_encoding
42
+ self.headings: dict[str, dict[str, str]] = OrderedDict()
43
+ self.headings[self.default_heading] = OrderedDict()
44
+ self.headings["env"] = OrderedDict()
45
+
46
+ def __getitem__(self, key: str) -> dict[str, str] | None:
47
+ return self.headings.get(key)
48
+
49
+ @classmethod
50
+ def from_file(cls, path: str, environ: dict[str, str]) -> "Vexrc":
51
+ """Make a Vexrc instance from given file in given environ."""
52
+ instance = cls()
53
+ instance.read(path, environ)
54
+ return instance
55
+
56
+ def read(self, path: str, environ: dict[str, str]) -> None:
57
+ """Read data from file into this vexrc instance."""
58
+ try:
59
+ with open(path, "rb") as inp:
60
+ parsing = parse_vexrc(inp, environ)
61
+ for heading, key, value in parsing:
62
+ heading = self.default_heading if heading is None else heading
63
+ if heading not in self.headings:
64
+ self.headings[heading] = OrderedDict()
65
+ self.headings[heading][key] = value
66
+ except FileNotFoundError:
67
+ return None
68
+
69
+ def get_ve_base(self, environ: dict[str, str]) -> str:
70
+ """Find a directory to look for virtualenvs in."""
71
+ # set ve_base to a path we can look for virtualenvs:
72
+ # 1. .vexrc
73
+ # 2. WORKON_HOME (as defined for virtualenvwrapper's benefit)
74
+ # 3. $HOME/.virtualenvs
75
+ ve_base_value: str | None = self.headings[self.default_heading].get(
76
+ "virtualenvs"
77
+ )
78
+ ve_base: str = ""
79
+ if ve_base_value:
80
+ ve_base = os.path.expanduser(ve_base_value)
81
+ else:
82
+ ve_base = environ.get("WORKON_HOME", "")
83
+
84
+ if not ve_base:
85
+ home: str = ""
86
+ if platform.system() == "Windows":
87
+ _win_drive: str = environ.get("HOMEDRIVE", "")
88
+ home_path: str = environ.get("HOMEPATH", "")
89
+ if home_path:
90
+ home = os.path.join(_win_drive, home_path)
91
+ else:
92
+ home = os.path.expanduser("~")
93
+ else:
94
+ home = environ.get("HOME", "")
95
+ if not home:
96
+ home = os.path.expanduser("~")
97
+
98
+ if not home:
99
+ return ""
100
+ ve_base = os.path.join(home, ".virtualenvs")
101
+
102
+ return ve_base
103
+
104
+ def get_shell(self, environ: dict[str, str]) -> list[str] | None:
105
+ """Find a command to run."""
106
+ command: str | None = self.headings[self.default_heading].get("shell")
107
+ if not command and os.name != "nt":
108
+ command = environ.get("SHELL", "")
109
+ return shlex.split(command) if command else None
110
+
111
+ def get_default_python(self, environ: dict[str, str]) -> str | None:
112
+ """Find a command to run."""
113
+ return self.headings[self.default_heading].get("python")
114
+
115
+
116
+ def extract_heading(line: str) -> str | None:
117
+ """Return heading in given line or None if it's not a heading."""
118
+ match: Any = _HEADING_RE.match(line)
119
+ return match.group(1) if match else None
120
+
121
+
122
+ def extract_key_value(line: str, environ: dict[str, str]) -> tuple[str, str] | None:
123
+ """Return key, value from given line if present, else return None."""
124
+ segments: list[str] = line.split("=", 1)
125
+ if len(segments) < 2:
126
+ return None
127
+ key, value = segments
128
+ value = value.strip()
129
+ if value:
130
+ if value.startswith("'") and _SQUOTE_RE.match(value):
131
+ value = value[1:-1]
132
+ elif value.startswith('"') and _DQUOTE_RE.match(value):
133
+ template: str = value[1:-1]
134
+ try:
135
+ value = template.format(**environ)
136
+ except KeyError:
137
+ # Fallback to literal if env var missing?
138
+ pass
139
+ value = value.strip()
140
+ key = key.strip()
141
+ return key, value
142
+
143
+
144
+ def parse_vexrc(
145
+ inp: Any, environ: dict[str, str]
146
+ ) -> Generator[tuple[str | None, str, str], None, None]:
147
+ """Iterator yielding key/value pairs from given stream."""
148
+ heading: str | None = None
149
+ errors: list[Any] = []
150
+ for line_number, line_bytes in enumerate(inp):
151
+ line = line_bytes.decode("utf-8")
152
+ if not line.strip():
153
+ continue
154
+ extracted_heading: str | None = extract_heading(line)
155
+ if extracted_heading is not None:
156
+ heading = extracted_heading
157
+ continue
158
+ kv_tuple: tuple[str, str] | None = extract_key_value(line, environ)
159
+ if kv_tuple is None:
160
+ errors.append((line_number, line))
161
+ continue
162
+ yield heading, kv_tuple[0], kv_tuple[1]
163
+
164
+ if errors:
165
+ raise InvalidConfigError(getattr(inp, "name", "unknown"), errors)
@@ -0,0 +1,60 @@
1
+ """Exceptions for vex."""
2
+
3
+
4
+ class InvalidArgument(Exception):
5
+ """Base class for exceptions raised by anything under main()."""
6
+
7
+ def __init__(self, message: str) -> None:
8
+ self.message: str = message
9
+ super().__init__(message)
10
+
11
+
12
+ class NoVirtualenvName(InvalidArgument):
13
+ """No virtualenv name was given."""
14
+
15
+
16
+ class NoVirtualenvsDirectory(InvalidArgument):
17
+ """There is no directory to find named virtualenvs in."""
18
+
19
+
20
+ class OtherShell(InvalidArgument):
21
+ """The given argument to --shell-config is not recognized."""
22
+
23
+
24
+ class UnknownArguments(InvalidArgument):
25
+ """Unknown arguments were given on the command line."""
26
+
27
+
28
+ class InvalidVexrc(InvalidArgument):
29
+ """Config file specified or required but absent or unparseable."""
30
+
31
+
32
+ class InvalidVirtualenv(InvalidArgument):
33
+ """No usable virtualenv was found."""
34
+
35
+
36
+ class InvalidCommand(InvalidArgument):
37
+ """No runnable command was found."""
38
+
39
+
40
+ class InvalidCwd(InvalidArgument):
41
+ """cwd specified or required but unusable."""
42
+
43
+
44
+ class BadConfig(InvalidArgument):
45
+ """Fatal conditions encountered on the way to run."""
46
+
47
+
48
+ class VirtualenvAlreadyMade(InvalidArgument):
49
+ """Virtualenv already exists."""
50
+
51
+
52
+ class VirtualenvNotMade(InvalidArgument):
53
+ """Could not make virtualenv."""
54
+
55
+
56
+ class VirtualenvNotRemoved(InvalidArgument):
57
+ """Virtualenv could not be removed."""
58
+
59
+
60
+ CommandNotFoundError = FileNotFoundError
File without changes
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env python3
2
+ print("not python")