cvat-cli 2.71.0__tar.gz → 2.74.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.
Files changed (32) hide show
  1. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/PKG-INFO +3 -2
  2. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/pyproject.toml +2 -1
  3. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/commands_all.py +2 -0
  4. cvat_cli-2.74.0/src/cvat_cli/_internal/commands_profile.py +173 -0
  5. cvat_cli-2.74.0/src/cvat_cli/_internal/utils.py +61 -0
  6. cvat_cli-2.74.0/src/cvat_cli/version.py +1 -0
  7. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli.egg-info/PKG-INFO +3 -2
  8. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli.egg-info/SOURCES.txt +1 -0
  9. cvat_cli-2.74.0/src/cvat_cli.egg-info/requires.txt +4 -0
  10. cvat_cli-2.71.0/src/cvat_cli/_internal/utils.py +0 -9
  11. cvat_cli-2.71.0/src/cvat_cli/version.py +0 -1
  12. cvat_cli-2.71.0/src/cvat_cli.egg-info/requires.txt +0 -3
  13. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/README.md +0 -0
  14. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/setup.cfg +0 -0
  15. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/__init__.py +0 -0
  16. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/__main__.py +0 -0
  17. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/__init__.py +0 -0
  18. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/agent.py +0 -0
  19. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/agent_driver.py +0 -0
  20. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/agent_driver_detection.py +0 -0
  21. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/agent_driver_interaction.py +0 -0
  22. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/agent_driver_tracking.py +0 -0
  23. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/command_base.py +0 -0
  24. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/commands_config.py +0 -0
  25. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/commands_functions.py +0 -0
  26. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/commands_projects.py +0 -0
  27. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/commands_tasks.py +0 -0
  28. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/common.py +0 -0
  29. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli/_internal/parsers.py +0 -0
  30. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli.egg-info/dependency_links.txt +0 -0
  31. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli.egg-info/entry_points.txt +0 -0
  32. {cvat_cli-2.71.0 → cvat_cli-2.74.0}/src/cvat_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cvat-cli
3
- Version: 2.71.0
3
+ Version: 2.74.0
4
4
  Summary: Command-line client for CVAT
5
5
  Author-email: "CVAT.ai Corporation" <support@cvat.ai>
6
6
  License-Expression: MIT
@@ -9,8 +9,9 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: cvat-sdk==2.71.0
12
+ Requires-Dist: cvat-sdk==2.74.0
13
13
  Requires-Dist: attrs>=24.2.0
14
+ Requires-Dist: json-with-comments==1.2.10
14
15
  Requires-Dist: Pillow>=10.3.0
15
16
 
16
17
  # Command-line client for CVAT
@@ -16,9 +16,10 @@ classifiers = [
16
16
  ]
17
17
  requires-python = ">=3.10"
18
18
  dependencies = [
19
- "cvat-sdk==2.71.0",
19
+ "cvat-sdk==2.74.0",
20
20
 
21
21
  "attrs>=24.2.0",
22
+ "json-with-comments==1.2.10",
22
23
  "Pillow>=10.3.0",
23
24
  ]
24
25
 
@@ -5,6 +5,7 @@
5
5
  from .command_base import CommandGroup, DeprecatedAlias
6
6
  from .commands_config import COMMANDS as COMMANDS_CONFIG
7
7
  from .commands_functions import COMMANDS as COMMANDS_FUNCTIONS
8
+ from .commands_profile import COMMANDS as COMMANDS_PROFILE
8
9
  from .commands_projects import COMMANDS as COMMANDS_PROJECTS
9
10
  from .commands_tasks import COMMANDS as COMMANDS_TASKS
10
11
 
@@ -12,6 +13,7 @@ COMMANDS = CommandGroup(description="Perform operations on CVAT resources.")
12
13
 
13
14
  COMMANDS.add_command("config", COMMANDS_CONFIG)
14
15
  COMMANDS.add_command("function", COMMANDS_FUNCTIONS)
16
+ COMMANDS.add_command("profile", COMMANDS_PROFILE)
15
17
  COMMANDS.add_command("project", COMMANDS_PROJECTS)
16
18
  COMMANDS.add_command("task", COMMANDS_TASKS)
17
19
 
@@ -0,0 +1,173 @@
1
+ # Copyright (C) CVAT.ai Corporation
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ from __future__ import annotations
6
+
7
+ import argparse
8
+ import getpass
9
+ from pathlib import Path
10
+ from urllib.parse import urlsplit
11
+
12
+ from cvat_sdk.core.auth import DEFAULT_SERVER, AuthStore, ProfileEntry
13
+ from cvat_sdk.core.client import AccessTokenCredentials, Client, Config
14
+ from cvat_sdk.core.utils import normalize_server_url
15
+
16
+ from .command_base import CommandGroup
17
+ from .common import CriticalError
18
+ from .utils import fetch_current_access_token_name, get_current_time_iso, read_token_file
19
+
20
+ COMMANDS = CommandGroup(description="Manage saved CVAT authentication profiles.")
21
+
22
+
23
+ @COMMANDS.command_class("list")
24
+ class ProfileList:
25
+ needs_client = False
26
+ description = "List saved profiles, marking the default one."
27
+
28
+ def configure_parser(self, parser: argparse.ArgumentParser) -> None:
29
+ parser.add_argument(
30
+ "--names-only", action="store_true", help="print profile names only (one per line)"
31
+ )
32
+
33
+ def execute(self, args: argparse.Namespace) -> None:
34
+ store = AuthStore()
35
+ profiles = store.list_profiles()
36
+ default = store.get_default_profile()
37
+ default_name = default[0] if default is not None else None
38
+
39
+ for name in sorted(profiles):
40
+ if args.names_only:
41
+ print(name)
42
+ else:
43
+ marker = "(default)" if name == default_name else ""
44
+ print(f"{name}\t{profiles[name].server}\t{marker}".rstrip())
45
+
46
+
47
+ @COMMANDS.command_class("default")
48
+ class ProfileDefault:
49
+ needs_client = False
50
+ description = "Print, set, or unset the default profile."
51
+
52
+ def configure_parser(self, parser: argparse.ArgumentParser) -> None:
53
+ parser.add_argument("name", nargs="?", default=None, help="profile to make default")
54
+ parser.add_argument("--unset", action="store_true", help="clear the default profile")
55
+
56
+ def execute(self, args: argparse.Namespace) -> None:
57
+ store = AuthStore()
58
+
59
+ if args.unset and args.name is not None:
60
+ raise CriticalError("Cannot combine a profile name with '--unset'.")
61
+
62
+ if args.unset:
63
+ store.clear_default_profile()
64
+ print("Default profile cleared.")
65
+ elif args.name is not None:
66
+ try:
67
+ store.set_default_profile(args.name)
68
+ except KeyError:
69
+ raise CriticalError(f"Unknown profile '{args.name}'. Run 'cvat-cli profile list'.")
70
+ print(f"Default profile is now '{args.name}'.")
71
+ else:
72
+ default = store.get_default_profile()
73
+ if default is None:
74
+ raise CriticalError("No default profile is set.")
75
+ print(default[0])
76
+
77
+
78
+ @COMMANDS.command_class("delete")
79
+ class ProfileDelete:
80
+ needs_client = False
81
+ description = (
82
+ "Remove a saved profile. Does not revoke the server-side token. "
83
+ "If it was the default, the default becomes unset."
84
+ )
85
+
86
+ def configure_parser(self, parser: argparse.ArgumentParser) -> None:
87
+ parser.add_argument("name", help="profile to remove")
88
+
89
+ def execute(self, args: argparse.Namespace) -> None:
90
+ store = AuthStore()
91
+ try:
92
+ store.remove_profile(args.name)
93
+ except KeyError:
94
+ raise CriticalError(f"Unknown profile '{args.name}'. Run 'cvat-cli profile list'.")
95
+ print(f"Removed profile '{args.name}'.")
96
+
97
+
98
+ @COMMANDS.command_class("create")
99
+ class ProfileCreate:
100
+ needs_client = False
101
+ description = (
102
+ "Save a Personal Access Token (PAT) and the server info into a local profile. "
103
+ "A PAT must be created on the server manually first. "
104
+ "Read more: https://docs.cvat.ai/docs/api_sdk/access_tokens/"
105
+ )
106
+
107
+ def configure_parser(self, parser: argparse.ArgumentParser) -> None:
108
+ parser.add_argument("--name", default=None, help="profile name (unique)")
109
+ parser.add_argument("token", nargs="?", default=None, help="PAT (omit to be prompted)")
110
+ parser.add_argument("--set-default", action="store_true", help="mark as default profile")
111
+ parser.add_argument("--force", action="store_true", help="overwrite an existing profile")
112
+ parser.add_argument(
113
+ "--file",
114
+ type=Path,
115
+ default=None,
116
+ help=(
117
+ "read the PAT from a file; accepts plain tokens and JSONC envelopes. "
118
+ "'--server-host' overrides the envelope server"
119
+ ),
120
+ )
121
+
122
+ def execute(self, args: argparse.Namespace) -> None:
123
+ store = AuthStore()
124
+
125
+ envelope_server = envelope_name = None
126
+ if args.file is not None:
127
+ if args.token is not None:
128
+ raise CriticalError("Cannot combine a PAT argument with '--file'.")
129
+ try:
130
+ token, envelope_server, envelope_name = read_token_file(args.file)
131
+ except (OSError, UnicodeError, ValueError) as e:
132
+ raise CriticalError(f"Cannot read token file '{args.file}': {e}") from e
133
+ elif args.token is not None:
134
+ token = args.token
135
+ else:
136
+ token = None
137
+
138
+ server = (
139
+ args.server_host or envelope_server or store.get_default_server() or DEFAULT_SERVER
140
+ ).rstrip("/")
141
+ if args.server_port:
142
+ parsed_url = urlsplit(("https://" if "://" not in server else "") + server)
143
+ if parsed_url.port:
144
+ raise CriticalError(
145
+ "A server URL with a port and '--server-port' cannot be used together. "
146
+ "Please specify only one port."
147
+ )
148
+ server = f"{server}:{args.server_port}"
149
+ server = normalize_server_url(server)
150
+
151
+ if token is None:
152
+ token = getpass.getpass(f"Personal Access Token (PAT) for '{server}': ")
153
+ if not token:
154
+ raise CriticalError("A non-empty PAT is required.")
155
+
156
+ name = args.name or envelope_name
157
+ if name is None:
158
+ with Client(
159
+ url=server, config=Config(verify_ssl=not args.insecure), check_server_version=False
160
+ ) as client:
161
+ client.login(AccessTokenCredentials(token))
162
+ name = fetch_current_access_token_name(client)
163
+
164
+ if store.get_profile(name) is not None and not args.force:
165
+ raise CriticalError(f"Profile '{name}' already exists. Pass '--force' to overwrite.")
166
+
167
+ store.put_profile(
168
+ name,
169
+ ProfileEntry(server=server, token=token, created_date=get_current_time_iso()),
170
+ set_default=args.set_default,
171
+ )
172
+ suffix = " (set as default)" if store.get_default_profile()[0] == name else ""
173
+ print(f"Saved profile '{name}' for {server}{suffix}.")
@@ -0,0 +1,61 @@
1
+ # Copyright (C) CVAT.ai Corporation
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ from __future__ import annotations
6
+
7
+ from datetime import datetime, timezone
8
+ from json import JSONDecodeError
9
+ from pathlib import Path
10
+
11
+ import jsonc
12
+ from cvat_sdk import Client
13
+
14
+
15
+ def popattr(obj, name):
16
+ value = getattr(obj, name)
17
+ delattr(obj, name)
18
+ return value
19
+
20
+
21
+ def get_current_time_iso() -> str:
22
+ return datetime.now(timezone.utc).isoformat()
23
+
24
+
25
+ def fetch_current_access_token_name(client: Client) -> str:
26
+ access_token, _ = client.api_client.auth_api.retrieve_access_tokens_self()
27
+ return access_token.name
28
+
29
+
30
+ def read_token_file(path: Path) -> tuple[str, str | None, str | None]:
31
+ """Read a PAT from a plain-text token file or a JSONC envelope."""
32
+ if not path.is_file():
33
+ raise ValueError("path must be a regular file")
34
+
35
+ text = path.read_text(encoding="utf-8")
36
+ if not text:
37
+ # jsonc.loads raises IndexError for empty strings:
38
+ # https://github.com/n-takumasa/json-with-comments/issues/48
39
+ return "", None, None
40
+
41
+ try:
42
+ doc = jsonc.loads(text)
43
+ except JSONDecodeError:
44
+ return text.strip(), None, None
45
+
46
+ if not isinstance(doc, dict):
47
+ return text.strip(), None, None
48
+
49
+ token = doc.get("token")
50
+ if not isinstance(token, str):
51
+ raise ValueError("JSON envelope field 'token' must be a string")
52
+
53
+ server = doc.get("server")
54
+ if server is not None and not isinstance(server, str):
55
+ raise ValueError("JSON envelope field 'server' must be a string")
56
+
57
+ name = doc.get("name")
58
+ if name is not None and not isinstance(name, str):
59
+ raise ValueError("JSON envelope field 'name' must be a string")
60
+
61
+ return token, server, name
@@ -0,0 +1 @@
1
+ VERSION = "2.74.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cvat-cli
3
- Version: 2.71.0
3
+ Version: 2.74.0
4
4
  Summary: Command-line client for CVAT
5
5
  Author-email: "CVAT.ai Corporation" <support@cvat.ai>
6
6
  License-Expression: MIT
@@ -9,8 +9,9 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Operating System :: OS Independent
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: cvat-sdk==2.71.0
12
+ Requires-Dist: cvat-sdk==2.74.0
13
13
  Requires-Dist: attrs>=24.2.0
14
+ Requires-Dist: json-with-comments==1.2.10
14
15
  Requires-Dist: Pillow>=10.3.0
15
16
 
16
17
  # Command-line client for CVAT
@@ -19,6 +19,7 @@ src/cvat_cli/_internal/command_base.py
19
19
  src/cvat_cli/_internal/commands_all.py
20
20
  src/cvat_cli/_internal/commands_config.py
21
21
  src/cvat_cli/_internal/commands_functions.py
22
+ src/cvat_cli/_internal/commands_profile.py
22
23
  src/cvat_cli/_internal/commands_projects.py
23
24
  src/cvat_cli/_internal/commands_tasks.py
24
25
  src/cvat_cli/_internal/common.py
@@ -0,0 +1,4 @@
1
+ cvat-sdk==2.74.0
2
+ attrs>=24.2.0
3
+ json-with-comments==1.2.10
4
+ Pillow>=10.3.0
@@ -1,9 +0,0 @@
1
- # Copyright (C) CVAT.ai Corporation
2
- #
3
- # SPDX-License-Identifier: MIT
4
-
5
-
6
- def popattr(obj, name):
7
- value = getattr(obj, name)
8
- delattr(obj, name)
9
- return value
@@ -1 +0,0 @@
1
- VERSION = "2.71.0"
@@ -1,3 +0,0 @@
1
- cvat-sdk==2.71.0
2
- attrs>=24.2.0
3
- Pillow>=10.3.0
File without changes
File without changes