Skip to content

Commit 99fd496

Browse files
committed
feat(cli.py): add json_output option to datalines_list command for JSON format output
fix(cli.py): handle project selection error more gracefully in datalines_select command test(cli.py): add tests for datalines_list and datalines_get commands to ensure functionality and output correctness
1 parent b2cc34c commit 99fd496

File tree

2 files changed

+250
-23
lines changed

2 files changed

+250
-23
lines changed

infactory_client/cli.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,10 @@ def datasource_create(
612612

613613
@datalines_app.command(name="list")
614614
def datalines_list(
615-
project_id: str | None = typer.Option(None, help="Project ID to list datalines for")
615+
project_id: str | None = typer.Option(
616+
None, help="Project ID to list datalines for"
617+
),
618+
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
616619
):
617620
"""List datalines."""
618621
client = get_client()
@@ -632,13 +635,32 @@ def datalines_list(
632635
typer.echo("No datalines found")
633636
return
634637

638+
if json_output:
639+
datalines_data = [
640+
{
641+
"id": dl.id,
642+
"name": dl.name
643+
or dl.data_model.get("schemaT", {}).get("name", dl.name),
644+
# "data_model": dl.data_model,
645+
# "schema_code": dl.schema_code,
646+
"project_id": dl.project_id,
647+
"dataobject_id": dl.dataobject_id,
648+
# "created_at": dl.created_at,
649+
# "updated_at": dl.updated_at,
650+
# "deleted_at": dl.deleted_at,
651+
}
652+
for dl in datalines
653+
]
654+
print(json.dumps(datalines_data))
655+
return
656+
635657
table = Table()
636658
table.add_column("ID")
637659
table.add_column("Name")
638660

639661
for dl in datalines:
640662
name = dl.name
641-
if dl.data_model.get("schemaT"):
663+
if dl.data_model and dl.data_model.get("schemaT"):
642664
name = dl.data_model["schemaT"].get("name", name) or name
643665
table.add_row(dl.id, name)
644666

@@ -660,16 +682,15 @@ def datalines_select(
660682
if model and code:
661683
typer.echo("Error: --model and --code cannot be used together", err=True)
662684
raise typer.Exit(1)
663-
if not model and not code:
664-
model = True
665685

666-
try:
667-
if not client.state.project_id:
668-
typer.echo(
669-
"No project selected. Please select a project first with 'nf projects select'"
670-
)
671-
return
686+
if not client.state.project_id:
687+
typer.echo(
688+
"No project selected. Please select a project first with 'nf projects select'",
689+
err=True,
690+
)
691+
raise typer.Exit(1)
672692

693+
try:
673694
datalines = client.datalines.list(project_id=client.state.project_id)
674695

675696
if not datalines:
@@ -686,10 +707,7 @@ def datalines_select(
686707
table.add_column("Name")
687708

688709
for num, dl in choices.items():
689-
name = dl.name
690-
if dl.data_model.get("schemaT"):
691-
name = dl.data_model["schemaT"].get("name", name) or name
692-
table.add_row(num, dl.id, name)
710+
table.add_row(num, dl.id, dl.name)
693711

694712
console.print(table)
695713

@@ -703,12 +721,12 @@ def datalines_select(
703721
selected_dataline = choices[choice]
704722

705723
if model and selected_dataline.data_model:
706-
typer.echo(json.dumps(selected_dataline.data_model, indent=2))
724+
print(json.dumps(selected_dataline.data_model, indent=2))
707725
elif code and selected_dataline.schema_code:
708-
typer.echo(selected_dataline.schema_code)
726+
print(selected_dataline.schema_code)
709727
else:
710728
typer.echo(
711-
f"Dataline: {selected_dataline.name} (ID: {selected_dataline.id})"
729+
f"\nSelected dataline: {selected_dataline.name} (ID: {selected_dataline.id})"
712730
)
713731

714732
except Exception as e:
@@ -725,13 +743,11 @@ def datalines_get(
725743
"""Get a dataline by ID."""
726744
client = get_client()
727745

728-
if model and code:
729-
typer.echo("Error: --model and --code cannot be used together", err=True)
730-
raise typer.Exit(1)
731-
if not model and not code:
732-
model = True
733-
734746
try:
747+
if model and code:
748+
typer.echo("Error: --model and --code cannot be used together", err=True)
749+
raise typer.Exit(1)
750+
735751
dataline = client.datalines.get(dataline_id)
736752

737753
if model and dataline.data_model:

tests/test_cli_resources.py

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,217 @@ def test_datasource_create(self):
398398
self.assertIn("Type: mysql", result.stdout)
399399
self.assertIn("URI:", result.stdout)
400400

401+
def test_datalines_list(self):
402+
"""Test dataline listing"""
403+
# First select an organization, team, and project
404+
result = self.runner.invoke(app, ["orgs", "list", "--json"])
405+
self.assertEqual(result.exit_code, 0)
406+
orgs_data = json.loads(result.stdout)
407+
408+
if not orgs_data:
409+
self.skipTest("No organizations available for testing")
410+
411+
# Set organization
412+
org_id = orgs_data[0]["id"]
413+
result = self.runner.invoke(app, ["orgs", "set", org_id])
414+
self.assertEqual(result.exit_code, 0)
415+
416+
# Get and set team
417+
result = self.runner.invoke(app, ["teams", "list", "--json"])
418+
self.assertEqual(result.exit_code, 0)
419+
teams_data = json.loads(result.stdout)
420+
421+
if not teams_data:
422+
self.skipTest("No teams available for testing")
423+
424+
team_id = teams_data[0]["id"]
425+
result = self.runner.invoke(app, ["teams", "set", team_id])
426+
self.assertEqual(result.exit_code, 0)
427+
428+
# Get and set project
429+
result = self.runner.invoke(app, ["projects", "list", "--json"])
430+
self.assertEqual(result.exit_code, 0)
431+
projects_data = json.loads(result.stdout)
432+
433+
if not projects_data:
434+
self.skipTest("No projects available for testing")
435+
436+
project_id = projects_data[0]["id"]
437+
result = self.runner.invoke(app, ["projects", "set", project_id])
438+
self.assertEqual(result.exit_code, 0)
439+
440+
# Test datalines list without project ID (using current project)
441+
result = self.runner.invoke(app, ["datalines", "list"])
442+
self.assertEqual(result.exit_code, 0)
443+
self.assertIn("ID", result.stdout)
444+
self.assertIn("Name", result.stdout)
445+
446+
# Test datalines list with explicit project ID
447+
result = self.runner.invoke(
448+
app, ["datalines", "list", "--project-id", project_id]
449+
)
450+
self.assertEqual(result.exit_code, 0)
451+
self.assertIn("ID", result.stdout)
452+
self.assertIn("Name", result.stdout)
453+
454+
# Test JSON output
455+
result = self.runner.invoke(app, ["datalines", "list", "--json"])
456+
self.assertEqual(result.exit_code, 0)
457+
if "No datalines found" not in result.stdout:
458+
datalines_data = json.loads(result.stdout)
459+
self.assertIsInstance(datalines_data, list)
460+
if datalines_data: # If there are datalines
461+
self.assertIn("id", datalines_data[0])
462+
self.assertIn("name", datalines_data[0])
463+
464+
# Test JSON output with explicit project ID
465+
result = self.runner.invoke(
466+
app, ["datalines", "list", "--json", "--project-id", project_id]
467+
)
468+
self.assertEqual(result.exit_code, 0)
469+
if "No datalines found" not in result.stdout:
470+
datalines_data = json.loads(result.stdout)
471+
self.assertIsInstance(datalines_data, list)
472+
if datalines_data: # If there are datalines
473+
self.assertIn("id", datalines_data[0])
474+
self.assertIn("name", datalines_data[0])
475+
476+
def test_datalines_get(self):
477+
"""Test getting a dataline by ID"""
478+
# First select an organization, team, and project
479+
result = self.runner.invoke(app, ["orgs", "list", "--json"])
480+
self.assertEqual(result.exit_code, 0)
481+
orgs_data = json.loads(result.stdout)
482+
483+
if not orgs_data:
484+
self.skipTest("No organizations available for testing")
485+
486+
# Set organization
487+
org_id = orgs_data[0]["id"]
488+
result = self.runner.invoke(app, ["orgs", "set", org_id])
489+
self.assertEqual(result.exit_code, 0)
490+
491+
# Get and set team
492+
result = self.runner.invoke(app, ["teams", "list", "--json"])
493+
self.assertEqual(result.exit_code, 0)
494+
teams_data = json.loads(result.stdout)
495+
496+
if not teams_data:
497+
self.skipTest("No teams available for testing")
498+
499+
team_id = teams_data[0]["id"]
500+
result = self.runner.invoke(app, ["teams", "set", team_id])
501+
self.assertEqual(result.exit_code, 0)
502+
503+
# Get and set project
504+
result = self.runner.invoke(app, ["projects", "list", "--json"])
505+
self.assertEqual(result.exit_code, 0)
506+
projects_data = json.loads(result.stdout)
507+
508+
if not projects_data:
509+
self.skipTest("No projects available for testing")
510+
511+
project_id = projects_data[0]["id"]
512+
result = self.runner.invoke(app, ["projects", "set", project_id])
513+
self.assertEqual(result.exit_code, 0)
514+
515+
# First get a list of datalines
516+
result = self.runner.invoke(app, ["datalines", "list", "--json"])
517+
self.assertEqual(result.exit_code, 0)
518+
519+
datalines = json.loads(result.stdout)
520+
521+
# If we have datalines, test get command
522+
if len(datalines) > 0:
523+
# Get the first dataline ID from the output
524+
dataline_id = datalines[0]["id"]
525+
526+
# Test basic get
527+
result = self.runner.invoke(app, ["datalines", "get", dataline_id])
528+
self.assertEqual(result.exit_code, 0)
529+
self.assertIn(dataline_id, result.stdout)
530+
531+
# Test get with --model flag
532+
result = self.runner.invoke(
533+
app, ["datalines", "get", dataline_id, "--model"]
534+
)
535+
self.assertEqual(result.exit_code, 0)
536+
# Note: We can't guarantee valid JSON output as it depends on the data
537+
538+
# Test get with --code flag
539+
result = self.runner.invoke(
540+
app, ["datalines", "get", dataline_id, "--code"]
541+
)
542+
self.assertEqual(result.exit_code, 0)
543+
# Note: We can't guarantee schema code exists
544+
545+
# Test error case: model and code flags together
546+
result = self.runner.invoke(
547+
app, ["datalines", "get", dataline_id, "--model", "--code"]
548+
)
549+
self.assertEqual(result.exit_code, 1)
550+
self.assertIn(
551+
"Error: --model and --code cannot be used together", result.stdout
552+
)
553+
554+
# Test error case: invalid ID
555+
result = self.runner.invoke(app, ["datalines", "get", "invalid-id"])
556+
self.assertNotEqual(result.exit_code, 0)
557+
else:
558+
self.skipTest("No datalines available for testing")
559+
560+
def test_datalines_select(self):
561+
"""Test interactive dataline selection"""
562+
# First select an organization, team, and project
563+
result = self.runner.invoke(app, ["orgs", "list", "--json"])
564+
self.assertEqual(result.exit_code, 0)
565+
orgs_data = json.loads(result.stdout)
566+
567+
if not orgs_data:
568+
self.skipTest("No organizations available for testing")
569+
570+
# Set organization
571+
org_id = orgs_data[0]["id"]
572+
result = self.runner.invoke(app, ["orgs", "set", org_id])
573+
self.assertEqual(result.exit_code, 0)
574+
575+
# Get and set team
576+
result = self.runner.invoke(app, ["teams", "list", "--json"])
577+
self.assertEqual(result.exit_code, 0)
578+
teams_data = json.loads(result.stdout)
579+
580+
if not teams_data:
581+
self.skipTest("No teams available for testing")
582+
583+
team_id = teams_data[0]["id"]
584+
result = self.runner.invoke(app, ["teams", "set", team_id])
585+
self.assertEqual(result.exit_code, 0)
586+
587+
# Get and set project
588+
result = self.runner.invoke(app, ["projects", "list", "--json"])
589+
self.assertEqual(result.exit_code, 0)
590+
projects_data = json.loads(result.stdout)
591+
592+
if not projects_data:
593+
self.skipTest("No projects available for testing")
594+
595+
project_id = projects_data[0]["id"]
596+
result = self.runner.invoke(app, ["projects", "set", project_id])
597+
self.assertEqual(result.exit_code, 0)
598+
599+
# Test error case: model and code flags together
600+
result = self.runner.invoke(app, ["datalines", "select", "--model", "--code"])
601+
self.assertEqual(result.exit_code, 1)
602+
self.assertIn(
603+
"Error: --model and --code cannot be used together", result.stdout
604+
)
605+
606+
# Test basic select command (will show prompt but not proceed due to no input)
607+
result = self.runner.invoke(app, ["datalines", "select"])
608+
if "No datalines found" in result.stdout:
609+
self.skipTest("No datalines available for testing")
610+
self.assertIn("Select dataline number", result.stdout)
611+
401612

402613
if __name__ == "__main__":
403614
unittest.main()

0 commit comments

Comments
 (0)