unitysvc-services 0.1.10__py3-none-any.whl → 0.1.11__py3-none-any.whl

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.

Potentially problematic release.


This version of unitysvc-services might be problematic. Click here for more details.

@@ -17,6 +17,18 @@ from typing import Any
17
17
  import typer
18
18
  from rich.console import Console
19
19
 
20
+ from .interactive_prompt import (
21
+ LISTING_GROUPS,
22
+ OFFERING_GROUPS,
23
+ PROVIDER_GROUPS,
24
+ SELLER_GROUPS,
25
+ PromptEngine,
26
+ create_listing_data,
27
+ create_offering_data,
28
+ create_provider_data,
29
+ create_seller_data,
30
+ )
31
+
20
32
  try:
21
33
  import tomli_w
22
34
 
@@ -718,20 +730,46 @@ def init_offering(
718
730
  )
719
731
  raise typer.Exit(code=1)
720
732
  else:
721
- # Generate from schema
722
- console.print(f"[blue]Creating service offering:[/blue] {name}")
723
- console.print(f"[blue]Output directory:[/blue] {output_dir}")
724
- console.print(f"[blue]Format:[/blue] {format}\n")
733
+ # Interactive mode - prompt for values
734
+ console.print("[bold cyan]Creating service offering interactively[/bold cyan]")
735
+ console.print(f"[dim]Output directory:[/dim] {output_dir / name}")
736
+ console.print(f"[dim]Format:[/dim] {format}\n")
725
737
 
726
738
  try:
727
- create_schema_based_structure(
728
- dest_dir=output_dir / name,
729
- dir_name=name,
730
- schema_name="service_v1",
731
- format_type=format,
732
- force=False,
733
- )
734
- console.print(f"[green]✓[/green] Service offering created: {output_dir / name}")
739
+ # Create directory structure
740
+ offering_dir = output_dir / name
741
+ offering_dir.mkdir(parents=True, exist_ok=True)
742
+
743
+ # Create prompt engine
744
+ engine = PromptEngine(OFFERING_GROUPS)
745
+
746
+ # Prompt for all fields (pass name if provided via CLI)
747
+ user_input = engine.prompt_all(context={"name": name})
748
+
749
+ # Create offering data structure (pass offering_dir for document file validation)
750
+ offering_data = create_offering_data(user_input, offering_dir=offering_dir)
751
+
752
+ # Write service file
753
+ service_file = offering_dir / f"service.{format}"
754
+ if format == "json":
755
+ with open(service_file, "w") as f:
756
+ json.dump(offering_data, f, indent=2)
757
+ f.write("\n")
758
+ else: # toml
759
+ if not TOML_WRITE_AVAILABLE:
760
+ console.print(
761
+ "[red]✗[/red] TOML write support not available. Install tomli_w.",
762
+ style="bold red",
763
+ )
764
+ raise typer.Exit(code=1)
765
+ with open(service_file, "wb") as f:
766
+ tomli_w.dump(offering_data, f)
767
+
768
+ console.print(f"\n[green]✓[/green] Service offering created: {offering_dir}")
769
+ console.print(f" Added: {service_file.name}")
770
+ except typer.Abort:
771
+ console.print("[yellow]Service offering creation cancelled[/yellow]")
772
+ raise typer.Exit(code=1)
735
773
  except Exception as e:
736
774
  console.print(
737
775
  f"[red]✗[/red] Failed to create service offering: {e}",
@@ -797,20 +835,46 @@ def init_listing(
797
835
  )
798
836
  raise typer.Exit(code=1)
799
837
  else:
800
- # Generate from schema
801
- console.print(f"[blue]Creating service listing:[/blue] {name}")
802
- console.print(f"[blue]Output directory:[/blue] {output_dir}")
803
- console.print(f"[blue]Format:[/blue] {format}\n")
838
+ # Interactive mode - prompt for values
839
+ console.print("[bold cyan]Creating service listing interactively[/bold cyan]")
840
+ console.print(f"[dim]Output directory:[/dim] {output_dir / name}")
841
+ console.print(f"[dim]Format:[/dim] {format}\n")
804
842
 
805
843
  try:
806
- create_schema_based_structure(
807
- dest_dir=output_dir / name,
808
- dir_name=name,
809
- schema_name="listing_v1",
810
- format_type=format,
811
- force=False,
812
- )
813
- console.print(f"[green]✓[/green] Service listing created: {output_dir / name}")
844
+ # Create directory structure
845
+ listing_dir = output_dir / name
846
+ listing_dir.mkdir(parents=True, exist_ok=True)
847
+
848
+ # Create prompt engine
849
+ engine = PromptEngine(LISTING_GROUPS)
850
+
851
+ # Prompt for all fields (pass name if provided via CLI)
852
+ user_input = engine.prompt_all(context={"name": name})
853
+
854
+ # Create listing data structure (pass listing_dir for document file validation)
855
+ listing_data = create_listing_data(user_input, listing_dir=listing_dir)
856
+
857
+ # Write listing file
858
+ listing_file = listing_dir / f"listing.{format}"
859
+ if format == "json":
860
+ with open(listing_file, "w") as f:
861
+ json.dump(listing_data, f, indent=2)
862
+ f.write("\n")
863
+ else: # toml
864
+ if not TOML_WRITE_AVAILABLE:
865
+ console.print(
866
+ "[red]✗[/red] TOML write support not available. Install tomli_w.",
867
+ style="bold red",
868
+ )
869
+ raise typer.Exit(code=1)
870
+ with open(listing_file, "wb") as f:
871
+ tomli_w.dump(listing_data, f)
872
+
873
+ console.print(f"\n[green]✓[/green] Service listing created: {listing_dir}")
874
+ console.print(f" Added: {listing_file.name}")
875
+ except typer.Abort:
876
+ console.print("[yellow]Service listing creation cancelled[/yellow]")
877
+ raise typer.Exit(code=1)
814
878
  except Exception as e:
815
879
  console.print(
816
880
  f"[red]✗[/red] Failed to create service listing: {e}",
@@ -873,20 +937,46 @@ def init_provider(
873
937
  console.print(f"[red]✗[/red] Failed to create provider: {e}", style="bold red")
874
938
  raise typer.Exit(code=1)
875
939
  else:
876
- # Generate from schema
877
- console.print(f"[blue]Creating provider:[/blue] {name}")
878
- console.print(f"[blue]Output directory:[/blue] {output_dir}")
879
- console.print(f"[blue]Format:[/blue] {format}\n")
940
+ # Interactive mode - prompt for values
941
+ console.print("[bold cyan]Creating provider interactively[/bold cyan]")
942
+ console.print(f"[dim]Output directory:[/dim] {output_dir / name}")
943
+ console.print(f"[dim]Format:[/dim] {format}\n")
880
944
 
881
945
  try:
882
- create_schema_based_structure(
883
- dest_dir=output_dir / name,
884
- dir_name=name,
885
- schema_name="provider_v1",
886
- format_type=format,
887
- force=False,
888
- )
889
- console.print(f"[green]✓[/green] Provider created: {output_dir / name}")
946
+ # Create prompt engine
947
+ engine = PromptEngine(PROVIDER_GROUPS)
948
+
949
+ # Prompt for all fields (pass name if provided via CLI)
950
+ user_input = engine.prompt_all(context={"name": name})
951
+
952
+ # Create provider data structure
953
+ provider_data = create_provider_data(user_input)
954
+
955
+ # Create directory structure
956
+ provider_dir = output_dir / name
957
+ provider_dir.mkdir(parents=True, exist_ok=True)
958
+
959
+ # Write provider file
960
+ provider_file = provider_dir / f"provider.{format}"
961
+ if format == "json":
962
+ with open(provider_file, "w") as f:
963
+ json.dump(provider_data, f, indent=2)
964
+ f.write("\n")
965
+ else: # toml
966
+ if not TOML_WRITE_AVAILABLE:
967
+ console.print(
968
+ "[red]✗[/red] TOML write support not available. Install tomli_w.",
969
+ style="bold red",
970
+ )
971
+ raise typer.Exit(code=1)
972
+ with open(provider_file, "wb") as f:
973
+ tomli_w.dump(provider_data, f)
974
+
975
+ console.print(f"\n[green]✓[/green] Provider created: {provider_dir}")
976
+ console.print(f" Added: {provider_file.name}")
977
+ except typer.Abort:
978
+ console.print("[yellow]Provider creation cancelled[/yellow]")
979
+ raise typer.Exit(code=1)
890
980
  except Exception as e:
891
981
  console.print(f"[red]✗[/red] Failed to create provider: {e}", style="bold red")
892
982
  raise typer.Exit(code=1)
@@ -983,40 +1073,24 @@ def init_seller(
983
1073
  console.print(f"[red]✗[/red] Failed to create seller: {e}", style="bold red")
984
1074
  raise typer.Exit(code=1)
985
1075
  else:
986
- # Generate from schema
987
- console.print(f"[blue]Creating seller:[/blue] {name}")
988
- console.print(f"[blue]Output directory:[/blue] {output_dir}")
989
- console.print(f"[blue]Format:[/blue] {format}\n")
1076
+ # Interactive mode - prompt for values
1077
+ console.print("[bold cyan]Creating seller interactively[/bold cyan]")
1078
+ console.print(f"[dim]Output directory:[/dim] {output_dir}")
1079
+ console.print(f"[dim]Format:[/dim] {format}\n")
990
1080
 
991
1081
  try:
1082
+ # Create prompt engine
1083
+ engine = PromptEngine(SELLER_GROUPS)
1084
+
1085
+ # Prompt for all fields (pass name if provided via CLI)
1086
+ user_input = engine.prompt_all(context={"name": name})
1087
+
1088
+ # Create seller data structure
1089
+ seller_data = create_seller_data(user_input)
1090
+
992
1091
  # Ensure output directory exists
993
1092
  output_dir.mkdir(parents=True, exist_ok=True)
994
1093
 
995
- # Get schema directory
996
- pkg_path = Path(__file__).parent
997
- schema_dir = pkg_path / "schema"
998
-
999
- # Load schema to generate example
1000
- schema_file = schema_dir / "seller_v1.json"
1001
- if not schema_file.exists():
1002
- raise FileNotFoundError(f"Schema file not found: {schema_file}")
1003
-
1004
- with open(schema_file) as f:
1005
- json.load(f)
1006
-
1007
- # Create basic seller data from schema
1008
- seller_data = {
1009
- "schema": "seller_v1",
1010
- "time_created": datetime.utcnow().isoformat() + "Z",
1011
- "name": name,
1012
- "display_name": name.replace("-", " ").replace("_", " ").title(),
1013
- "seller_type": "individual",
1014
- "contact_email": "contact@example.com",
1015
- "description": f"{name} seller",
1016
- "is_active": True,
1017
- "is_verified": False,
1018
- }
1019
-
1020
1094
  # Write to file
1021
1095
  output_file = output_dir / f"seller.{format}"
1022
1096
  if format == "json":
@@ -1033,7 +1107,10 @@ def init_seller(
1033
1107
  with open(output_file, "wb") as f:
1034
1108
  tomli_w.dump(seller_data, f)
1035
1109
 
1036
- console.print(f"[green]✓[/green] Seller created: {output_file}")
1110
+ console.print(f"\n[green]✓[/green] Seller created: {output_file}")
1111
+ except typer.Abort:
1112
+ console.print("[yellow]Seller creation cancelled[/yellow]")
1113
+ raise typer.Exit(code=1)
1037
1114
  except Exception as e:
1038
1115
  console.print(f"[red]✗[/red] Failed to create seller: {e}", style="bold red")
1039
1116
  raise typer.Exit(code=1)
unitysvc_services/test.py CHANGED
@@ -1,12 +1,10 @@
1
1
  """Test command group - test code examples with upstream credentials."""
2
2
 
3
3
  import fnmatch
4
- import json
5
4
  import os
6
5
  import shutil
7
6
  import subprocess
8
7
  import tempfile
9
- import tomllib
10
8
  from pathlib import Path
11
9
  from typing import Any
12
10
 
@@ -154,26 +152,27 @@ def load_related_data(listing_file: Path) -> dict[str, Any]:
154
152
  return result
155
153
 
156
154
 
157
- def load_provider_credentials(provider_file: Path) -> dict[str, str] | None:
158
- """Load API key and endpoint from provider file.
155
+ def load_provider_credentials(listing_file: Path) -> dict[str, str] | None:
156
+ """Load API key and endpoint from service offering file.
159
157
 
160
158
  Args:
161
- provider_file: Path to provider.toml or provider.json
159
+ listing_file: Path to the listing file (used to locate the service offering)
162
160
 
163
161
  Returns:
164
162
  Dictionary with api_key and api_endpoint, or None if not found
165
163
  """
166
164
  try:
167
- if provider_file.suffix == ".toml":
168
- with open(provider_file, "rb") as f:
169
- provider_data = tomllib.load(f)
170
- else:
171
- with open(provider_file) as f:
172
- provider_data = json.load(f)
165
+ # Load related data including the offering
166
+ related_data = load_related_data(listing_file)
167
+ offering = related_data.get("offering", {})
168
+
169
+ if not offering:
170
+ return None
173
171
 
174
- access_info = provider_data.get("provider_access_info", {})
175
- api_key = access_info.get("api_key") or access_info.get("FIREWORKS_API_KEY")
176
- api_endpoint = access_info.get("api_endpoint") or access_info.get("FIREWORKS_API_BASE_URL")
172
+ # Extract credentials from upstream_access_interface
173
+ upstream_access = offering.get("upstream_access_interface", {})
174
+ api_key = upstream_access.get("api_key")
175
+ api_endpoint = upstream_access.get("api_endpoint")
177
176
 
178
177
  if api_key and api_endpoint:
179
178
  return {
@@ -181,7 +180,7 @@ def load_provider_credentials(provider_file: Path) -> dict[str, str] | None:
181
180
  "api_endpoint": str(api_endpoint),
182
181
  }
183
182
  except Exception as e:
184
- console.print(f"[yellow]Warning: Failed to load provider credentials: {e}[/yellow]")
183
+ console.print(f"[yellow]Warning: Failed to load service credentials: {e}[/yellow]")
185
184
 
186
185
  return None
187
186
 
@@ -610,28 +609,6 @@ def run(
610
609
 
611
610
  console.print(f"[blue]Scanning for listing files in:[/blue] {data_dir}\n")
612
611
 
613
- # Find all provider files first to get credentials
614
- provider_results = find_files_by_schema(data_dir, "provider_v1")
615
- provider_credentials: dict[str, dict[str, str]] = {}
616
-
617
- for provider_file, _format, provider_data in provider_results:
618
- prov_name = provider_data.get("name", "unknown")
619
-
620
- # Skip if provider filter is set and doesn't match
621
- if provider_name and prov_name != provider_name:
622
- continue
623
-
624
- credentials = load_provider_credentials(provider_file)
625
- if credentials:
626
- provider_credentials[prov_name] = credentials
627
- console.print(f"[green]✓[/green] Loaded credentials for provider: {prov_name}")
628
-
629
- if not provider_credentials:
630
- console.print("[yellow]No provider credentials found.[/yellow]")
631
- raise typer.Exit(code=0)
632
-
633
- console.print()
634
-
635
612
  # Find all listing files
636
613
  listing_results = find_files_by_schema(data_dir, "listing_v1")
637
614
 
@@ -642,7 +619,7 @@ def run(
642
619
  console.print(f"[cyan]Found {len(listing_results)} listing file(s)[/cyan]\n")
643
620
 
644
621
  # Extract code examples from all listings
645
- all_code_examples: list[tuple[dict[str, Any], str]] = []
622
+ all_code_examples: list[tuple[dict[str, Any], str, dict[str, str]]] = []
646
623
 
647
624
  for listing_file, _format, listing_data in listing_results:
648
625
  # Determine provider for this listing
@@ -661,8 +638,10 @@ def run(
661
638
  if provider_name and prov_name != provider_name:
662
639
  continue
663
640
 
664
- # Skip if we don't have credentials for this provider
665
- if prov_name not in provider_credentials:
641
+ # Load credentials from service offering for this listing
642
+ credentials = load_provider_credentials(listing_file)
643
+ if not credentials:
644
+ console.print(f"[yellow]⚠ No credentials found for listing: {listing_file}[/yellow]")
666
645
  continue
667
646
 
668
647
  # Filter by service directory name if patterns are provided
@@ -686,7 +665,7 @@ def run(
686
665
  if not file_path.endswith(test_file):
687
666
  continue
688
667
 
689
- all_code_examples.append((example, prov_name))
668
+ all_code_examples.append((example, prov_name, credentials))
690
669
 
691
670
  if not all_code_examples:
692
671
  console.print("[yellow]No code examples found in listings.[/yellow]")
@@ -697,13 +676,12 @@ def run(
697
676
  # Execute each code example
698
677
  results = []
699
678
 
700
- for example, prov_name in all_code_examples:
679
+ for example, prov_name, credentials in all_code_examples:
701
680
  service_name = example["service_name"]
702
681
  title = example["title"]
703
682
 
704
683
  console.print(f"[bold]Testing:[/bold] {service_name} - {title}")
705
684
 
706
- credentials = provider_credentials[prov_name]
707
685
  result = execute_code_example(example, credentials)
708
686
 
709
687
  results.append(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unitysvc-services
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: SDK for digital service providers on UnitySVC
5
5
  Author-email: Bo Peng <bo.peng@unitysvc.com>
6
6
  Maintainer-email: Bo Peng <bo.peng@unitysvc.com>
@@ -1,14 +1,15 @@
1
1
  unitysvc_services/__init__.py,sha256=J6F3RlZCJUVjhZoprfbrYCxe3l9ynQQbGO7pf7FyqlM,110
2
- unitysvc_services/api.py,sha256=d3xY4ElA4aCAl62xrwjZ6qIWUoYT-4Q8wJ8BJbyZzXI,11990
2
+ unitysvc_services/api.py,sha256=RgqTxaxg2YLM36ePzlxeOyFB3tJGQsTP0ZQD0Q8ssn0,11990
3
3
  unitysvc_services/cli.py,sha256=omHzrWk8iZJUjZTE5KCmEK1wnRGGnQk_BNV-hKqucnA,725
4
4
  unitysvc_services/format_data.py,sha256=Jl9Vj3fRX852fHSUa5DzO-oiFQwuQHC3WMCDNIlo1Lc,5460
5
+ unitysvc_services/interactive_prompt.py,sha256=cnadxhshsTYovNNO51_71FACIpMQMqaVv1vRPW-xFHc,39292
5
6
  unitysvc_services/list.py,sha256=QDp9BByaoeFeJxXJN9RQ-jU99mH9Guq9ampfXCbpZmI,7033
6
- unitysvc_services/populate.py,sha256=jiqS2D3_widV6siPe3OBvw7ZdG9MuddEIOuTUCtMM5c,7605
7
- unitysvc_services/publisher.py,sha256=7KFzQ3cB33t5t5LDUPYZ7LoP6LXoT9Y5PgqNzP-kOmk,61695
7
+ unitysvc_services/populate.py,sha256=lAbu-EMbvM3qk9P_MQ0sQc74IyZigcj-u3eUcgi9Qpw,8063
8
+ unitysvc_services/publisher.py,sha256=EQoqH8pJunjEj7ecN4Ot7UPgzNlVkIo9BssTztjOvss,67729
8
9
  unitysvc_services/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
10
  unitysvc_services/query.py,sha256=q0_g5YAl9cPlHpW7k7Y6A-t4fQSdI-_4Jl6g2KgkEm0,24049
10
- unitysvc_services/scaffold.py,sha256=Y73IX8vskImxSvxDgR0mvEFuAMYnBKfttn3bjcz3jmQ,40331
11
- unitysvc_services/test.py,sha256=Uf06_mgRcEGf9HHYzW2BGTzrDKwd3n7Xb60DFChP8kM,32472
11
+ unitysvc_services/scaffold.py,sha256=v4BVx3kRHSPj9QQR9UoGm4VSEQKe5ZbApjfh8zWNnWQ,43706
12
+ unitysvc_services/test.py,sha256=d9ToiTJB9nHsCjzBOGCLbP5epc8CfDCUi2w_J10Tk0I,31713
12
13
  unitysvc_services/update.py,sha256=K9swocTUnqqiSgARo6GmuzTzUySSpyqqPPW4xF7ZU-g,9659
13
14
  unitysvc_services/utils.py,sha256=4tEBdO90XpkS6j73ZXnz5dNLVXJaPUILWMwzk5_fUQ4,15276
14
15
  unitysvc_services/validator.py,sha256=NYoIWV2iMyjse1-mIVz2GnFXNDewLnJVDIDAjqnsBCs,30241
@@ -23,9 +24,9 @@ unitysvc_services/schema/listing_v1.json,sha256=gzSK5ncnqmcb44WPnv0FG9xyJ-wUznca
23
24
  unitysvc_services/schema/provider_v1.json,sha256=L2rudq1RcfAE67WJXmowJu5_YReqxioiQO0263SWaNc,22033
24
25
  unitysvc_services/schema/seller_v1.json,sha256=QhYuaJBugWVbgAEBhrSyYAPT1Ss_6Z0rz0lA2FhJOo8,8841
25
26
  unitysvc_services/schema/service_v1.json,sha256=sifCZzx0hT7k6tpDCkPUgXYG9e5OVUaeKudTjEPFO4E,24293
26
- unitysvc_services-0.1.10.dist-info/licenses/LICENSE,sha256=_p8V6A8OMPu2HIztn3O01v0-urZFwk0Dd3Yk_PTIlL8,1065
27
- unitysvc_services-0.1.10.dist-info/METADATA,sha256=oehP4td47B1x0c1Rg8zNO2OLlvdKvLhzbvqb5mIQCgk,7235
28
- unitysvc_services-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
- unitysvc_services-0.1.10.dist-info/entry_points.txt,sha256=RBhVHKky3rsOly4jVa29c7UAw5ZwNNWnttmtzozr5O0,97
30
- unitysvc_services-0.1.10.dist-info/top_level.txt,sha256=GIotQj-Ro2ruR7eupM1r58PWqIHTAq647ORL7E2kneo,18
31
- unitysvc_services-0.1.10.dist-info/RECORD,,
27
+ unitysvc_services-0.1.11.dist-info/licenses/LICENSE,sha256=_p8V6A8OMPu2HIztn3O01v0-urZFwk0Dd3Yk_PTIlL8,1065
28
+ unitysvc_services-0.1.11.dist-info/METADATA,sha256=6_cV9lPBvfTjh9eUiVvRuf2E0ThyFUz4BLQmSJUl49g,7235
29
+ unitysvc_services-0.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
+ unitysvc_services-0.1.11.dist-info/entry_points.txt,sha256=RBhVHKky3rsOly4jVa29c7UAw5ZwNNWnttmtzozr5O0,97
31
+ unitysvc_services-0.1.11.dist-info/top_level.txt,sha256=GIotQj-Ro2ruR7eupM1r58PWqIHTAq647ORL7E2kneo,18
32
+ unitysvc_services-0.1.11.dist-info/RECORD,,