Skip to content

Commit 406a19d

Browse files
yeldarbyclaude
andcommitted
fix(cli): default annotation group and improve project get display
- Default --annotation to the project name when not provided, so `project create` works without the flag (the API requires it). - Parse HTTP 422 response bodies to surface actionable error hints. - Add human-readable key-value output for `project get` instead of dumping raw JSON in non-JSON mode. - Use suppress_sdk_output context manager in create_project. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7ca9721 commit 406a19d

File tree

1 file changed

+48
-20
lines changed

1 file changed

+48
-20
lines changed

roboflow/cli/handlers/project.py

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,39 +110,67 @@ def _get_project(args: argparse.Namespace) -> None:
110110
output_error(args, str(exc), exit_code=3)
111111
return
112112

113-
import json
114-
115-
output(args, data, text=json.dumps(data, indent=2, default=str))
113+
project = data.get("project", data)
114+
lines = []
115+
field_map = [
116+
("Name", "name"),
117+
("ID", "id"),
118+
("Type", "type"),
119+
("License", "license"),
120+
("Annotation", "annotation"),
121+
("Classes", "classes"),
122+
("Images", "images"),
123+
("Versions", "versions"),
124+
("Created", "created"),
125+
("Updated", "updated"),
126+
("Public", "public"),
127+
]
128+
for label, key in field_map:
129+
if key in project:
130+
val = project[key]
131+
if isinstance(val, dict):
132+
val = ", ".join(f"{k}: {v}" for k, v in val.items())
133+
lines.append(f" {label:12s} {val}")
134+
text = "\n".join(lines) if lines else "(no project details)"
135+
136+
output(args, data, text=text)
116137

117138

118139
def _create_project(args: argparse.Namespace) -> None:
119-
import io
120-
import sys
121-
122140
import roboflow
123-
from roboflow.cli._output import output, output_error
141+
from roboflow.cli._output import output, output_error, suppress_sdk_output
124142

125-
# Suppress SDK status messages that pollute stdout (especially in --json mode)
126-
quiet = getattr(args, "json", False) or getattr(args, "quiet", False)
127-
if quiet:
128-
_orig_stdout = sys.stdout
129-
sys.stdout = io.StringIO()
130-
try:
131-
rf = roboflow.Roboflow()
132-
workspace = rf.workspace(args.workspace)
133-
finally:
134-
if quiet:
135-
sys.stdout = _orig_stdout
143+
annotation = args.annotation if args.annotation else args.name
144+
145+
with suppress_sdk_output(args):
146+
try:
147+
rf = roboflow.Roboflow()
148+
workspace = rf.workspace(args.workspace)
149+
except Exception as exc:
150+
output_error(args, str(exc))
151+
return
136152

137153
try:
138154
project = workspace.create_project(
139155
project_name=args.name,
140156
project_type=args.type,
141157
project_license=args.license,
142-
annotation=args.annotation,
158+
annotation=annotation,
143159
)
144160
except Exception as exc:
145-
output_error(args, str(exc))
161+
msg = str(exc)
162+
hint = None
163+
# Try to extract a useful message from HTTP 422 responses
164+
if hasattr(exc, "response"):
165+
try:
166+
body = exc.response.json() # type: ignore[union-attr]
167+
if "error" in body:
168+
hint = body["error"].get("message", None) if isinstance(body["error"], dict) else str(body["error"])
169+
elif "message" in body:
170+
hint = str(body["message"])
171+
except Exception:
172+
pass
173+
output_error(args, msg, hint=hint)
146174
return
147175

148176
data = {

0 commit comments

Comments
 (0)