pingintel-api 1.4.7__tar.gz → 1.4.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.
Files changed (59) hide show
  1. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/PKG-INFO +1 -1
  2. pingintel_api-1.4.8/examples/close_submissions.py +129 -0
  3. pingintel_api-1.4.8/src/pingintel_api/__about__.py +1 -0
  4. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingvision/pingvision_api_client.py +1 -1
  5. pingintel_api-1.4.7/src/pingintel_api/__about__.py +0 -1
  6. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/.claude/settings.json +0 -0
  7. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/.claude/settings.local.json +0 -0
  8. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/.gitignore +0 -0
  9. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/.pre-commit-config.yaml +0 -0
  10. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/LICENSE +0 -0
  11. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/README.md +0 -0
  12. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/SOV10 2026-02_Acc-STG.txt +0 -0
  13. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/Untitled-9.json5 +0 -0
  14. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/assignment_queue.xlsx +0 -0
  15. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/completed_submissions.xlsx +0 -0
  16. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/data/demo_email.eml +0 -0
  17. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/data/parse_sov_testfile.xlsx +0 -0
  18. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/find-amwins-missing-account-numbers.py +0 -0
  19. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-data/enhance_multiple_locations.py +0 -0
  20. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-data/enhance_one_location.py +0 -0
  21. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-data/pingdata_enhance.py +0 -0
  22. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-extraction/parse_sov.py +0 -0
  23. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-extraction/sovfixer_fix_sov.py +0 -0
  24. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-extraction/sovfixer_list_activity.py +0 -0
  25. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-extraction/sovfixer_reoutput_sov.py +0 -0
  26. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-vision/clear_and_triage_api.py +0 -0
  27. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-vision/pingvision_activity.py +0 -0
  28. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-vision/pingvision_clear_and_triage.py +0 -0
  29. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/ping-vision/send_and_track_submission.py +0 -0
  30. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/pingvision_assignment.py +0 -0
  31. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/pingvision_declination_flow.py +0 -0
  32. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/sovfixer_list_history.py +0 -0
  33. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/sovfixer_list_history_ping_None_1_run2.csv +0 -0
  34. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/sovfixerapi +0 -0
  35. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/test_reoutput_locations.csv +0 -0
  36. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/examples/test_sov.xlsx +0 -0
  37. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/generate_docs.py +0 -0
  38. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/justfile +0 -0
  39. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/output-data-f432c75e-b40e-11f0-9e68-3c58c2f91432-1.json +0 -0
  40. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/pyproject.toml +0 -0
  41. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/requirements.txt +0 -0
  42. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/__init__.py +0 -0
  43. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/api_client_base.py +0 -0
  44. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/common_types.py +0 -0
  45. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/constants.py +0 -0
  46. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingdata/pingdata_api_client.py +0 -0
  47. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingdata/types.py +0 -0
  48. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingdataapi_cmd.py +0 -0
  49. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingmaps/pingmaps_api_client.py +0 -0
  50. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingmaps/types.py +0 -0
  51. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingmapsapi_cmd.py +0 -0
  52. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingvision/types.py +0 -0
  53. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/pingvisionapi_cmd.py +0 -0
  54. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/sov_fixer/sov_fixer_api_client.py +0 -0
  55. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/sov_fixer/types.py +0 -0
  56. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/sovfixerapi_cmd.py +0 -0
  57. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/url_signature_factory.py +0 -0
  58. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/src/pingintel_api/utils.py +0 -0
  59. {pingintel_api-1.4.7 → pingintel_api-1.4.8}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pingintel-api
3
- Version: 1.4.7
3
+ Version: 1.4.8
4
4
  Summary: Python-based client to Ping Data Intelligence APIs
5
5
  Project-URL: Homepage, https://github.com/pingintel/pingintel-api
6
6
  Project-URL: Issues, https://github.com/pingintel/pingintel-api/issues
@@ -0,0 +1,129 @@
1
+ """
2
+ Set one or more PingVision submissions to a given workflow status.
3
+
4
+ Accepts pingids (e.g. p-ob-amw-agtdgc) or client_refs. Identifiers starting
5
+ with "p-" are treated as pingids; all others are looked up as client_refs.
6
+
7
+ Usage:
8
+ python close_submissions.py <id1> [id2 ...] --status <name> [options]
9
+
10
+ python close_submissions.py p-ob-amw-abc123 my-client-ref-456 --status Closed
11
+ python close_submissions.py p-ob-amw-abc123 --status Declined --env staging --dry-run
12
+ """
13
+
14
+ import argparse
15
+ import sys
16
+
17
+ from pingintel_api import PingVisionAPIClient
18
+
19
+
20
+ def resolve_pingids(client: PingVisionAPIClient, identifiers: list[str]) -> dict[str, str | None]:
21
+ """Return {identifier: pingid} for all identifiers. pingid is None if not found."""
22
+ result = {}
23
+ for ident in identifiers:
24
+ if ident.startswith("p-"):
25
+ result[ident] = ident
26
+ else:
27
+ activity = client.list_submission_activity(client_ref=ident, page_size=10)
28
+ submissions = activity.get("results", [])
29
+ if not submissions:
30
+ print(f" WARNING: No submission found for client_ref={ident!r}", file=sys.stderr)
31
+ result[ident] = None
32
+ elif len(submissions) > 1:
33
+ pingids = [s["id"] for s in submissions]
34
+ print(
35
+ f" WARNING: Multiple submissions found for client_ref={ident!r}: {pingids}. Skipping.",
36
+ file=sys.stderr,
37
+ )
38
+ result[ident] = None
39
+ else:
40
+ result[ident] = submissions[0]["id"]
41
+ return result
42
+
43
+
44
+ def find_status_uuid(client: PingVisionAPIClient, division_uuid: str, status_name: str) -> str:
45
+ statuses = client.list_submission_statuses(division=division_uuid)
46
+ matched = [s for s in statuses if s["name"].lower() == status_name.lower()]
47
+ if not matched:
48
+ available = [s["name"] for s in statuses]
49
+ raise RuntimeError(f"Status {status_name!r} not found. Available: {available}")
50
+ return matched[0]["uuid"]
51
+
52
+
53
+ def find_division_uuid(client: PingVisionAPIClient, team_name: str | None, division: str | None) -> str:
54
+ teams = client.list_teams()
55
+ if not teams:
56
+ raise RuntimeError("No teams found for this API token.")
57
+ if division:
58
+ matched = [
59
+ t for t in teams
60
+ if t["division_uuid"] == division
61
+ or t.get("division_name", "").lower() == division.lower()
62
+ or t.get("division_short_name", "").lower() == division.lower()
63
+ ]
64
+ if not matched:
65
+ available = [(t.get("division_short_name") or t["division_name"], t["division_uuid"]) for t in teams]
66
+ raise RuntimeError(f"Division {division!r} not found. Available: {available}")
67
+ return matched[0]["division_uuid"]
68
+ if team_name:
69
+ matched = [t for t in teams if t["team_name"] == team_name]
70
+ if not matched:
71
+ available = [t["team_name"] for t in teams]
72
+ raise RuntimeError(f"Team {team_name!r} not found. Available: {available}")
73
+ return matched[0]["division_uuid"]
74
+ if len(teams) == 1:
75
+ return teams[0]["division_uuid"]
76
+ names = [t["team_name"] for t in teams]
77
+ raise RuntimeError(f"Multiple teams found: {names}. Specify one with --team or --division.")
78
+
79
+
80
+ def main():
81
+ parser = argparse.ArgumentParser(description="Set PingVision submission workflow status.")
82
+ parser.add_argument("identifiers", nargs="+", help="pingids or client_refs to update")
83
+ parser.add_argument("--status", required=True, help="Target workflow status name (e.g. Closed, Declined)")
84
+ parser.add_argument("--env", default="prod", help="API environment (prod, staging, local). Default: prod")
85
+ parser.add_argument("--api-url", help="Override API URL (e.g. http://localhost:8002)")
86
+ parser.add_argument("--team", help="Team name for status lookup (required if multiple teams)")
87
+ parser.add_argument("--division", help="Division UUID (alternative to --team)")
88
+ parser.add_argument("--dry-run", action="store_true", help="Print what would happen without making changes")
89
+ args = parser.parse_args()
90
+
91
+ kwargs = {}
92
+ if args.api_url:
93
+ kwargs["api_url"] = args.api_url
94
+ else:
95
+ kwargs["environment"] = args.env
96
+
97
+ client = PingVisionAPIClient(**kwargs)
98
+
99
+ division_uuid = find_division_uuid(client, args.team, args.division)
100
+ status_uuid = find_status_uuid(client, division_uuid, args.status)
101
+ print(f"Status {args.status!r} UUID: {status_uuid}")
102
+
103
+ id_map = resolve_pingids(client, args.identifiers)
104
+
105
+ success, skipped, failed = 0, 0, 0
106
+ for ident, pingid in id_map.items():
107
+ if pingid is None:
108
+ skipped += 1
109
+ continue
110
+ label = pingid if ident == pingid else f"{pingid} (client_ref={ident!r})"
111
+ if args.dry_run:
112
+ print(f" DRY RUN: would set {label} -> {args.status!r}")
113
+ success += 1
114
+ continue
115
+ try:
116
+ client.change_status(pingid=pingid, workflow_status_id=status_uuid)
117
+ print(f" Updated {label} -> {args.status!r}")
118
+ success += 1
119
+ except Exception as e:
120
+ print(f" ERROR updating {label}: {e}", file=sys.stderr)
121
+ failed += 1
122
+
123
+ print(f"\nDone. {success} updated, {skipped} skipped, {failed} failed.")
124
+ if failed:
125
+ sys.exit(1)
126
+
127
+
128
+ if __name__ == "__main__":
129
+ main()
@@ -0,0 +1 @@
1
+ __version__ = "1.4.8"
@@ -182,7 +182,7 @@ class PingVisionAPIClient(APIClientBase):
182
182
  else:
183
183
  url = self.api_url + document_url
184
184
 
185
- assert url.startswith(self.api_url), f"document_url should start with {self.api_url} or / but got {url}"
185
+ # assert url.startswith(self.api_url), f"document_url should start with {self.api_url} or / but got {url}"
186
186
 
187
187
  response = self.get(url)
188
188
  raise_for_status(response)
@@ -1 +0,0 @@
1
- __version__ = "1.4.7"
File without changes
File without changes
File without changes
File without changes