Skip to content

Commit 10f1b3b

Browse files
authored
Release v1.5.0 (#26)
v1.5.0
2 parents d96620e + 01aacaf commit 10f1b3b

File tree

5 files changed

+141
-11
lines changed

5 files changed

+141
-11
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
# Changelog
22

3-
## [Unreleased](https://github.com/SallingGroup-AI-and-ML/venv-cli/tree/develop)
3+
## [v1.5.0](https://github.com/SallingGroup-AI-and-ML/venv-cli/releases/tag/v1.5.0) (2024-01-04)
4+
5+
### Major changes
6+
* Added `venv delete` command. [#25](https://github.com/SallingGroup-AI-and-ML/venv-cli/pull/25)
7+
8+
Running `venv delete` completely removes the virtual environment located in the current folder.
9+
10+
### Minor changes
11+
* Added `-s` alias for `--skip-lock` when running `venv install`. [#24](https://github.com/SallingGroup-AI-and-ML/venv-cli/pull/24)
12+
13+
### Internal changes
14+
* The `run_command` test helper function can now pass through inputs to the command that is being run.
415

516
## [v1.4.1](https://github.com/SallingGroup-AI-and-ML/venv-cli/releases/tag/v1.4.1) (2023-10-30)
617

src/venv-cli/completions/bash/venv_completion.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ _venv() {
55
cur_word="${COMP_WORDS[COMP_CWORD]}"
66
prev_word="${COMP_WORDS[COMP_CWORD-1]}"
77

8-
_subcommands="activate clear create deactivate install lock sync"
8+
_subcommands="activate clear create deactivate delete install lock sync"
99
subcommands=( $(compgen -W "${_subcommands}" -- "${cur_word}") )
1010
help_options=( $(compgen -W "-h --help" -- "${cur_word}") )
1111

@@ -39,6 +39,11 @@ _venv() {
3939
COMPREPLY+=( ${python_versions[*]} )
4040
COMPREPLY+=( ${help_options[*]} )
4141
;;
42+
"delete")
43+
# Generate completion for help_options plus the '-y' option
44+
COMPREPLY+=( ${help_options[*]} )
45+
COMPREPLY+=( $(compgen -W "-y" -- "${cur_word}") )
46+
;;
4247
"install")
4348
# Generate completions for requirement and lock file paths
4449
COMPREPLY+=( $(compgen -f -X '!(*.txt|*.lock)' -- "${cur_word}" | sort) )

src/venv-cli/venv.sh

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ _yellow="\033[01;33m"
99
_red="\033[31m"
1010

1111
# Version number has to follow pattern "^v\d+\.\d+\.\d+.*$"
12-
_version="v1.4.1"
12+
_version="v1.5.0"
1313

1414
# Valid VCS URL environment variable pattern
1515
# https://peps.python.org/pep-0610/#specification
@@ -163,15 +163,60 @@ venv::deactivate() {
163163
}
164164

165165

166+
venv::delete() {
167+
if venv::_check_if_help_requested "$1"; then
168+
echo "venv delete [-y]"
169+
echo
170+
echo "Delete the virtual environment located in the current folder."
171+
echo "If the environment is currently active, it will be deactivated first."
172+
echo
173+
echo "Examples:"
174+
echo "$ venv delete"
175+
echo "Are you sure you want to delete the virtual environment in .venv? [y/N]"
176+
echo "y"
177+
echo "$ Virtual environment deleted!"
178+
return "${_success}"
179+
fi
180+
181+
if [ ! -d .venv ]; then
182+
venv::color_echo "${_yellow}" "No virtual environment found, nothing to delete."
183+
return "${_success}"
184+
fi
185+
186+
# If -y is not supplied as input argument, prompt the user for confirmation
187+
if [ "$1" != "-y" ]; then
188+
echo "Are you sure you want to delete the virtual environment in .venv? [y/N]"
189+
read -r response
190+
191+
local accept_pattern="^([yY][eE][sS]|[yY])$"
192+
if [[ ! "${response}" =~ $accept_pattern ]]; then
193+
venv::color_echo "${_yellow}" "Aborting."
194+
return "${_success}"
195+
fi
196+
fi
197+
198+
venv::color_echo "${_yellow}" "Deleting virtual environment in .venv ..."
199+
if [ ! -z "${VIRTUAL_ENV}" ]; then
200+
venv::deactivate
201+
fi
202+
203+
if ! rm -rf .venv; then
204+
# If the virtual environment could not be deleted
205+
return "${_fail}"
206+
fi
207+
venv::color_echo "${_green}" "Virtual environment deleted!"
208+
}
209+
210+
166211
venv::install() {
167212
if venv::_check_if_help_requested "$1"; then
168-
echo "venv install [<requirements file>] [--skip-lock] [<install args>]"
213+
echo "venv install [<requirements file>] [--skip-lock|-s] [<install args>]"
169214
echo
170215
echo "Clear the environment, then install requirements from <requirements file>,"
171216
echo "like 'requirements.txt' or 'requirements.lock'."
172217
echo "Installed packages are then locked into the corresponding .lock-file,"
173218
echo "e.g. 'venv install requirements.txt' will lock packages into 'requirements.lock'."
174-
echo "This step is skipped if '--skip-lock' is specified, or when installing"
219+
echo "This step is skipped if '--skip-lock' or '-s' is specified, or when installing"
175220
echo "directly from a .lock-file."
176221
echo
177222
echo "The <requirements file> must be in the form '*requirements.[txt|lock]'."
@@ -185,12 +230,12 @@ venv::install() {
185230
echo
186231
echo "$ venv install dev-requirements.txt"
187232
echo
188-
echo "$ venv install requirements.txt --skip-lock --no-cache"
233+
echo "$ venv install requirements.txt --skip-lock|-s --no-cache"
189234
return "${_success}"
190235
fi
191236

192237
local requirements_file
193-
if [ -z "$1" ] || [ "$1" = "--skip-lock" ]; then
238+
if [ -z "$1" ] || [ "$1" = "--skip-lock" ] || [ "$1" = "-s" ]; then
194239
# If no filename was passed
195240
requirements_file="requirements.txt"
196241

@@ -206,7 +251,7 @@ venv::install() {
206251
fi
207252

208253
local skip_lock=false
209-
if [ "$1" = "--skip-lock" ]; then
254+
if [ "$1" = "--skip-lock" ] || [ "$1" = "-s" ]; then
210255
skip_lock=true
211256
shift
212257
fi
@@ -358,6 +403,7 @@ venv::help() {
358403
echo
359404
echo "create Create a new virtual environment in the current folder"
360405
echo "activate Activate the virtual environment in the current folder"
406+
echo "delete Delete the virtual environment in the current folder"
361407
echo "install Install requirements from a requirements file in the current environment"
362408
echo "lock Lock installed requirements in a '.lock'-file"
363409
echo "clear Remove all installed packages in the current environment"
@@ -385,6 +431,7 @@ venv::main() {
385431

386432
create \
387433
| activate \
434+
| delete \
388435
| install \
389436
| lock \
390437
| clear \

tests/helpers.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import sys
44
from functools import wraps
55
from pathlib import Path
6-
from typing import Callable
6+
from typing import Callable, Optional
77

88
from tests.types import P, RawFilesDict, RequirementsBase, RequirementsDict
99

@@ -27,13 +27,29 @@ def _command_setup(venv_cli_path: Path, activate: bool = False) -> list[str]:
2727
return [*bash, full_command]
2828

2929

30-
def run_command(commands: str | list[str], cwd: Path = Path.cwd(), activated: bool = False) -> None:
30+
def run_command(
31+
commands: str | list[str],
32+
cwd: Path = Path.cwd(),
33+
activated: bool = False,
34+
command_input: Optional[str] = None,
35+
) -> None:
36+
"""Run a command in a subprocess, optionally activating the virtual environment first
37+
38+
Args:
39+
commands: The command(s) to run.
40+
cwd: The directory to run the command in. Defaults to the current working directory.
41+
activated: Whether to activate the virtual environment before running the command.
42+
command_input: The input to pass to the command. Defaults to None.
43+
44+
Raises:
45+
subprocess.CalledProcessError: If the command returns a non-zero exit code.
46+
"""
3147
input_commands = [commands] if isinstance(commands, str) else commands
3248

3349
setup_commands = _command_setup(venv_cli_path=_venv_cli_path, activate=activated)
3450
all_commands = [*setup_commands[:-1], setup_commands[-1] + "; ".join(input_commands)]
3551

36-
result = subprocess.run(all_commands, cwd=cwd)
52+
result = subprocess.run(all_commands, cwd=cwd, input=command_input, text=True)
3753
result.check_returncode()
3854

3955

tests/test_venv_delete.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
import pytest_cases
5+
6+
from tests.helpers import run_command
7+
8+
9+
@pytest.mark.order(after="test_venv_activate.py::test_venv_activate")
10+
@pytest_cases.parametrize("yes", ["y", "yes", "Y", "Yes", "YES"])
11+
@pytest_cases.parametrize("activated", [False, True])
12+
def test_venv_delete_ask_confirmation_yes(activated: bool, yes: str, tmp_path: Path):
13+
venv_path = tmp_path / ".venv"
14+
15+
# Execute: Create, then delete, the virtual environment
16+
run_command("venv delete", command_input=yes, cwd=tmp_path, activated=activated)
17+
18+
# Verify: check that the virtual environment directory no longer exists
19+
assert not venv_path.is_dir()
20+
21+
# Test that trying to delete again doesn't cause an error
22+
run_command("venv delete", command_input=yes, cwd=tmp_path, activated=activated)
23+
24+
25+
@pytest.mark.order(after="test_venv_activate.py::test_venv_activate")
26+
@pytest_cases.parametrize("no", ["", "n", "N", "No", "NO", "asd"])
27+
@pytest_cases.parametrize("activated", [False, True])
28+
def test_venv_delete_ask_confirmation_no(activated: bool, no: str, tmp_path: Path):
29+
venv_path = tmp_path / ".venv"
30+
31+
# Execute: Create, then try to delete, the virtual environment, but say no
32+
run_command("venv delete", command_input=no, cwd=tmp_path, activated=activated)
33+
34+
if activated:
35+
# Verify: check that the virtual environment directory still exists (if it was created)
36+
assert venv_path.is_dir()
37+
38+
39+
@pytest.mark.order(after="test_venv_activate.py::test_venv_activate")
40+
@pytest_cases.parametrize("activated", [False, True])
41+
def test_venv_delete_no_confirmation(activated: bool, tmp_path: Path):
42+
venv_path = tmp_path / ".venv"
43+
44+
# Execute: Create, then delete, the virtual environment
45+
run_command("venv delete -y", cwd=tmp_path, activated=activated)
46+
47+
# Verify: check that the virtual environment directory no longer exists
48+
assert not venv_path.is_dir()
49+
50+
# Test that trying to delete again doesn't cause an error
51+
run_command("venv delete -y", cwd=tmp_path, activated=activated)

0 commit comments

Comments
 (0)