pipecatcloud 0.2.6__tar.gz → 0.2.8__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.
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/CHANGELOG.md +23 -0
- {pipecatcloud-0.2.6/src/pipecatcloud.egg-info → pipecatcloud-0.2.8}/PKG-INFO +1 -1
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/pyproject.toml +3 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/agent.py +9 -7
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/api.py +14 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/agent.py +67 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/docker.py +1 -1
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/init.py +18 -1
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8/src/pipecatcloud.egg-info}/PKG-INFO +1 -1
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud.egg-info/SOURCES.txt +1 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud.egg-info/entry_points.txt +3 -0
- pipecatcloud-0.2.8/tests/test_agent_stop.py +99 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/.github/workflows/publish-pypi.yml +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/.github/workflows/publish-test.yml +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/.github/workflows/tests.yml +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/.gitignore +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/LICENSE +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/README.md +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/pipecat-cloud.png +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/pytest.ini +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/setup.cfg +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/__init__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/__main__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/__version__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/__init__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/async_utils.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/auth_utils.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/console_utils.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/deploy_utils.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/_utils/local_runner.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/__init__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/api.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/__init__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/auth.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/deploy.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/organizations.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/run.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/commands/secrets.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/config.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/cli/entry_point.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/config.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/exception.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/py.typed +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/session.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud/smallwebrtc/session_manager.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud.egg-info/requires.txt +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/src/pipecatcloud.egg-info/top_level.txt +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/tests/__init__.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/tests/test_agent_sessions.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/tests/test_docker_commands.py +0 -0
- {pipecatcloud-0.2.6 → pipecatcloud-0.2.8}/tests/test_managed_keys.py +0 -0
|
@@ -5,6 +5,29 @@ All notable changes to **Pipecat Cloud** will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.8] - 2025-10-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Register pipecat cloud commands as `pipecat-cli` extensions.
|
|
13
|
+
|
|
14
|
+
## [0.2.7] - 2025-10-21
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Added a `stop` command to `pcc agent` that allows stopping an ongoing Pipecat
|
|
19
|
+
Cloud session.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Fallback `RunnerArguments` now include a `body` field in the base class.
|
|
24
|
+
|
|
25
|
+
### Deprecated
|
|
26
|
+
|
|
27
|
+
- The `pcc init` command is now deprecated and will be removed in a future
|
|
28
|
+
version. Use the [Pipecat CLI](https://github.com/pipecat-ai/pipecat-cli)
|
|
29
|
+
instead.
|
|
30
|
+
|
|
8
31
|
## [0.2.6] - 2025-10-09
|
|
9
32
|
|
|
10
33
|
### Added
|
|
@@ -42,6 +42,9 @@ dev = [
|
|
|
42
42
|
pcc = "pipecatcloud.__main__:main"
|
|
43
43
|
pipecatcloud = "pipecatcloud.__main__:main"
|
|
44
44
|
|
|
45
|
+
[project.entry-points."pipecat_cli.extensions"]
|
|
46
|
+
cloud = "pipecatcloud.cli.entry_point:entrypoint_cli_typer"
|
|
47
|
+
|
|
45
48
|
[tool.setuptools]
|
|
46
49
|
package-dir = {"" = "src"}
|
|
47
50
|
|
|
@@ -15,8 +15,8 @@ try:
|
|
|
15
15
|
from pipecat.runner.types import (
|
|
16
16
|
DailyRunnerArguments,
|
|
17
17
|
RunnerArguments,
|
|
18
|
-
WebSocketRunnerArguments,
|
|
19
18
|
SmallWebRTCRunnerArguments,
|
|
19
|
+
WebSocketRunnerArguments,
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
_PIPECAT_RUNNER_TYPES_AVAILABLE = True
|
|
@@ -33,9 +33,10 @@ except ImportError:
|
|
|
33
33
|
will be removed in a future release.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
-
handle_sigint: bool = field(init=False)
|
|
37
|
-
handle_sigterm: bool = field(init=False)
|
|
38
|
-
pipeline_idle_timeout_secs: int = field(init=False)
|
|
36
|
+
handle_sigint: bool = field(init=False, kw_only=True)
|
|
37
|
+
handle_sigterm: bool = field(init=False, kw_only=True)
|
|
38
|
+
pipeline_idle_timeout_secs: int = field(init=False, kw_only=True)
|
|
39
|
+
body: Optional[Any] = field(default_factory=dict, kw_only=True)
|
|
39
40
|
|
|
40
41
|
def __post_init__(self):
|
|
41
42
|
self.handle_sigint = False
|
|
@@ -52,7 +53,6 @@ except ImportError:
|
|
|
52
53
|
|
|
53
54
|
room_url: str
|
|
54
55
|
token: str
|
|
55
|
-
body: Any
|
|
56
56
|
|
|
57
57
|
@dataclass
|
|
58
58
|
class WebSocketRunnerArguments(RunnerArguments):
|
|
@@ -63,7 +63,6 @@ except ImportError:
|
|
|
63
63
|
"""
|
|
64
64
|
|
|
65
65
|
websocket: WebSocket
|
|
66
|
-
body: Any
|
|
67
66
|
|
|
68
67
|
@dataclass
|
|
69
68
|
class SmallWebRTCRunnerArguments(RunnerArguments):
|
|
@@ -112,7 +111,9 @@ class PipecatSessionArguments(RunnerArguments, SessionArguments):
|
|
|
112
111
|
For best compatibility, install: pip install pipecatcloud[pipecat]
|
|
113
112
|
"""
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
def __post_init__(self):
|
|
115
|
+
RunnerArguments.__post_init__(self)
|
|
116
|
+
_warn_standalone_usage()
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
@dataclass
|
|
@@ -144,6 +145,7 @@ class WebSocketSessionArguments(WebSocketRunnerArguments, SessionArguments):
|
|
|
144
145
|
WebSocketRunnerArguments.__post_init__(self)
|
|
145
146
|
_warn_standalone_usage()
|
|
146
147
|
|
|
148
|
+
|
|
147
149
|
@dataclass
|
|
148
150
|
class SmallWebRTCSessionArguments(SmallWebRTCRunnerArguments, SessionArguments):
|
|
149
151
|
"""SmallWebRTCTransport based agent session arguments.
|
|
@@ -438,3 +438,17 @@ class _API:
|
|
|
438
438
|
@property
|
|
439
439
|
def agent_sessions(self):
|
|
440
440
|
return self.create_api_method(self._agent_sessions)
|
|
441
|
+
|
|
442
|
+
async def _agent_session_terminate(self, agent_name: str, session_id: str, org: str) -> dict | None:
|
|
443
|
+
url = f"{self.construct_api_url('services_sessions_path').format(org=org, service=agent_name)}/{session_id}"
|
|
444
|
+
return await self._base_request("DELETE", url, not_found_is_empty=True)
|
|
445
|
+
|
|
446
|
+
@property
|
|
447
|
+
def agent_session_terminate(self):
|
|
448
|
+
"""Terminate an active session for an agent.
|
|
449
|
+
Args:
|
|
450
|
+
agent_name: Name of the agent
|
|
451
|
+
session_id: ID of the session to terminate
|
|
452
|
+
org: Organization ID
|
|
453
|
+
"""
|
|
454
|
+
return self.create_api_method(self._agent_session_terminate)
|
|
@@ -730,3 +730,70 @@ async def start(
|
|
|
730
730
|
url = f"{daily_room}?t={daily_token}"
|
|
731
731
|
console.print("\nJoin your session by visiting the link below:")
|
|
732
732
|
console.print(f"[link={url}]{url}[/link]")
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
@agent_cli.command(name="stop", help="Stop an active agent session")
|
|
736
|
+
@synchronizer.create_blocking
|
|
737
|
+
@requires_login
|
|
738
|
+
@with_deploy_config
|
|
739
|
+
async def stop(
|
|
740
|
+
deploy_config=typer.Option(None, hidden=True),
|
|
741
|
+
agent_name: str = typer.Argument(None, help="Name of the agent e.g. 'my-agent'"),
|
|
742
|
+
session_id: str = typer.Option(
|
|
743
|
+
...,
|
|
744
|
+
"--session-id",
|
|
745
|
+
"-s",
|
|
746
|
+
help="ID of the session to stop",
|
|
747
|
+
),
|
|
748
|
+
organization: str = typer.Option(
|
|
749
|
+
None, "--organization", "-o", help="Organization which the agent belongs to"
|
|
750
|
+
),
|
|
751
|
+
force: bool = typer.Option(
|
|
752
|
+
False,
|
|
753
|
+
"--force",
|
|
754
|
+
"-f",
|
|
755
|
+
help="Bypass prompt for confirmation",
|
|
756
|
+
),
|
|
757
|
+
):
|
|
758
|
+
org = organization or config.get("org")
|
|
759
|
+
|
|
760
|
+
# Load values from deployment config file (if one exists)
|
|
761
|
+
partial_config = deploy_config or DeployConfigParams()
|
|
762
|
+
|
|
763
|
+
# Get agent name from argument or deploy config
|
|
764
|
+
if not agent_name:
|
|
765
|
+
if partial_config and partial_config.agent_name:
|
|
766
|
+
agent_name = partial_config.agent_name
|
|
767
|
+
else:
|
|
768
|
+
console.error("No target agent name provided")
|
|
769
|
+
return typer.Exit(1)
|
|
770
|
+
|
|
771
|
+
# Confirm stop request
|
|
772
|
+
if not force:
|
|
773
|
+
console.print(
|
|
774
|
+
Panel(
|
|
775
|
+
f"Agent Name: {agent_name}\n"
|
|
776
|
+
f"Session ID: {session_id}",
|
|
777
|
+
title=f"[bold]Stop Session[/bold]",
|
|
778
|
+
title_align="left",
|
|
779
|
+
border_style="yellow",
|
|
780
|
+
)
|
|
781
|
+
)
|
|
782
|
+
if not await questionary.confirm(
|
|
783
|
+
"Are you sure you want to stop this session?"
|
|
784
|
+
).ask_async():
|
|
785
|
+
console.print("[bold]Aborting stop request[/bold]")
|
|
786
|
+
return typer.Exit(1)
|
|
787
|
+
|
|
788
|
+
with console.status(
|
|
789
|
+
f"[dim]Stopping session [bold]'{session_id}'[/bold] for agent [bold]'{agent_name}'[/bold][/dim]",
|
|
790
|
+
spinner="dots",
|
|
791
|
+
):
|
|
792
|
+
data, error = await API.agent_session_terminate(
|
|
793
|
+
agent_name=agent_name, session_id=session_id, org=org
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
if error:
|
|
797
|
+
return typer.Exit(1)
|
|
798
|
+
|
|
799
|
+
console.success(f"Session '{session_id}' stopped successfully")
|
|
@@ -336,7 +336,7 @@ async def build_push(
|
|
|
336
336
|
console.print("\n[dim]To deploy this image, update your pcc-deploy.toml:[/dim]")
|
|
337
337
|
console.print(f' [bold]image = "{version_tag}"[/bold]')
|
|
338
338
|
console.print("\n[dim]Then run:[/dim]")
|
|
339
|
-
console.print(" [bold]
|
|
339
|
+
console.print(" [bold]pipecat cloud deploy[/bold]")
|
|
340
340
|
|
|
341
341
|
|
|
342
342
|
def create_docker_command(app: typer.Typer):
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
+
import warnings
|
|
8
9
|
import zipfile
|
|
9
10
|
from typing import Set
|
|
10
11
|
|
|
@@ -40,9 +41,25 @@ def check_existing_files() -> Set[str]:
|
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
def create_init_command(app: typer.Typer):
|
|
43
|
-
@app.command(
|
|
44
|
+
@app.command(
|
|
45
|
+
name="init",
|
|
46
|
+
help="[DEPRECATED] Initialize project directory with template files",
|
|
47
|
+
deprecated=True,
|
|
48
|
+
)
|
|
44
49
|
@synchronizer.create_blocking
|
|
45
50
|
async def init():
|
|
51
|
+
warnings.warn(
|
|
52
|
+
"The 'pcc init' command is deprecated and will be removed in a future version. "
|
|
53
|
+
"Please use the Pipecat CLI instead: https://github.com/pipecat-ai/pipecat-cli",
|
|
54
|
+
DeprecationWarning,
|
|
55
|
+
stacklevel=2,
|
|
56
|
+
)
|
|
57
|
+
console.print(
|
|
58
|
+
"[yellow]Warning:[/yellow] The 'pcc init' command is deprecated and will be removed in a future version.\n"
|
|
59
|
+
"Please use the Pipecat CLI instead: "
|
|
60
|
+
"[link=https://github.com/pipecat-ai/pipecat-cli]https://github.com/pipecat-ai/pipecat-cli[/link]"
|
|
61
|
+
)
|
|
62
|
+
|
|
46
63
|
if not await questionary.confirm(
|
|
47
64
|
"This will download the latest starter project to the current directory. Continue?"
|
|
48
65
|
).ask_async():
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for the 'pcc agent stop' command.
|
|
3
|
+
|
|
4
|
+
Tests focus on core behaviors and edge cases, not implementation details.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
import typer
|
|
9
|
+
from unittest.mock import patch, AsyncMock, MagicMock
|
|
10
|
+
|
|
11
|
+
# Import the function under test from local source
|
|
12
|
+
from src.pipecatcloud.cli.commands.agent import stop
|
|
13
|
+
|
|
14
|
+
# Test constants
|
|
15
|
+
TEST_ORG = "test-org"
|
|
16
|
+
TEST_AGENT = "test-agent"
|
|
17
|
+
TEST_SESSION_ID = "session-123"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestAgentStopCommand:
|
|
21
|
+
"""Test the 'pcc agent stop' command behaviors."""
|
|
22
|
+
|
|
23
|
+
def test_stop_respects_force_flag(self):
|
|
24
|
+
"""Verify force flag skips confirmation when set to True."""
|
|
25
|
+
with patch('src.pipecatcloud.cli.commands.agent.console') as mock_console, \
|
|
26
|
+
patch('src.pipecatcloud.cli.commands.agent.config') as mock_config, \
|
|
27
|
+
patch('src.pipecatcloud.cli.commands.agent.questionary') as mock_questionary, \
|
|
28
|
+
patch('src.pipecatcloud.cli.commands.agent.DeployConfigParams') as mock_params:
|
|
29
|
+
|
|
30
|
+
mock_config.get.return_value = TEST_ORG
|
|
31
|
+
mock_params.return_value = MagicMock(agent_name=TEST_AGENT)
|
|
32
|
+
# Mock questionary - should NOT be called when force=True
|
|
33
|
+
mock_questionary.confirm.return_value.ask_async = AsyncMock()
|
|
34
|
+
|
|
35
|
+
# Act with force=True
|
|
36
|
+
stop(
|
|
37
|
+
deploy_config=None,
|
|
38
|
+
agent_name=TEST_AGENT,
|
|
39
|
+
session_id=TEST_SESSION_ID,
|
|
40
|
+
organization=TEST_ORG,
|
|
41
|
+
force=True,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Assert
|
|
45
|
+
# questionary.confirm should not be called when force=True
|
|
46
|
+
mock_questionary.confirm.assert_not_called()
|
|
47
|
+
|
|
48
|
+
def test_stop_shows_confirmation_without_force(self):
|
|
49
|
+
"""Verify confirmation prompt is shown when force is False."""
|
|
50
|
+
with patch('src.pipecatcloud.cli.commands.agent.console') as mock_console, \
|
|
51
|
+
patch('src.pipecatcloud.cli.commands.agent.config') as mock_config, \
|
|
52
|
+
patch('src.pipecatcloud.cli.commands.agent.questionary') as mock_questionary, \
|
|
53
|
+
patch('src.pipecatcloud.cli.commands.agent.DeployConfigParams') as mock_params:
|
|
54
|
+
|
|
55
|
+
mock_config.get.return_value = TEST_ORG
|
|
56
|
+
mock_params.return_value = MagicMock(agent_name=TEST_AGENT)
|
|
57
|
+
# User agrees to the confirmation
|
|
58
|
+
mock_questionary.confirm.return_value.ask_async = AsyncMock(return_value=True)
|
|
59
|
+
|
|
60
|
+
# Act with force=False
|
|
61
|
+
stop(
|
|
62
|
+
deploy_config=None,
|
|
63
|
+
agent_name=TEST_AGENT,
|
|
64
|
+
session_id=TEST_SESSION_ID,
|
|
65
|
+
organization=TEST_ORG,
|
|
66
|
+
force=False,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Assert
|
|
70
|
+
# questionary.confirm should be called when force=False
|
|
71
|
+
mock_questionary.confirm.assert_called_once()
|
|
72
|
+
|
|
73
|
+
def test_stop_aborts_on_user_rejection(self):
|
|
74
|
+
"""Verify command aborts when user rejects the confirmation."""
|
|
75
|
+
with patch('src.pipecatcloud.cli.commands.agent.console') as mock_console, \
|
|
76
|
+
patch('src.pipecatcloud.cli.commands.agent.config') as mock_config, \
|
|
77
|
+
patch('src.pipecatcloud.cli.commands.agent.questionary') as mock_questionary, \
|
|
78
|
+
patch('src.pipecatcloud.cli.commands.agent.DeployConfigParams') as mock_params:
|
|
79
|
+
|
|
80
|
+
mock_config.get.return_value = TEST_ORG
|
|
81
|
+
mock_params.return_value = MagicMock(agent_name=TEST_AGENT)
|
|
82
|
+
# User rejects the confirmation
|
|
83
|
+
mock_questionary.confirm.return_value.ask_async = AsyncMock(return_value=False)
|
|
84
|
+
|
|
85
|
+
# Act
|
|
86
|
+
result = stop(
|
|
87
|
+
deploy_config=None,
|
|
88
|
+
agent_name=TEST_AGENT,
|
|
89
|
+
session_id=TEST_SESSION_ID,
|
|
90
|
+
organization=TEST_ORG,
|
|
91
|
+
force=False,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Assert
|
|
95
|
+
# Should exit with code 1 (abort)
|
|
96
|
+
assert isinstance(result, typer.Exit)
|
|
97
|
+
assert result.exit_code == 1
|
|
98
|
+
# Should display abort message
|
|
99
|
+
mock_console.print.assert_any_call("[bold]Aborting stop request[/bold]")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|