datalegion-cli 1.1.0__tar.gz → 1.2.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.
- datalegion_cli-1.2.0/.github/dependabot.yml +42 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/.github/workflows/ci.yml +6 -6
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/.github/workflows/release.yml +8 -8
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/PKG-INFO +22 -4
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/README.md +21 -3
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/pyproject.toml +1 -1
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/client.py +7 -4
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/commands/company.py +29 -27
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/commands/person.py +29 -27
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/commands/utility.py +68 -2
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_commands.py +85 -21
- datalegion_cli-1.2.0/uv.lock +645 -0
- datalegion_cli-1.1.0/uv.lock +0 -627
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/.gitignore +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/__init__.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/async_typer.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/commands/__init__.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/commands/credits.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/config.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/logging.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/main.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/output.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/src/datalegion_cli/update.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/__init__.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/conftest.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_client.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_config.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_logging.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_output.py +0 -0
- {datalegion_cli-1.1.0 → datalegion_cli-1.2.0}/tests/test_update.py +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "uv"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
day: "sunday"
|
|
8
|
+
time: "09:00"
|
|
9
|
+
timezone: "America/Los_Angeles"
|
|
10
|
+
cooldown:
|
|
11
|
+
default-days: 1
|
|
12
|
+
labels:
|
|
13
|
+
- "dependencies"
|
|
14
|
+
- "python"
|
|
15
|
+
commit-message:
|
|
16
|
+
prefix: "chore(deps)"
|
|
17
|
+
groups:
|
|
18
|
+
minor-patch:
|
|
19
|
+
patterns:
|
|
20
|
+
- "*"
|
|
21
|
+
update-types:
|
|
22
|
+
- "minor"
|
|
23
|
+
- "patch"
|
|
24
|
+
|
|
25
|
+
- package-ecosystem: "github-actions"
|
|
26
|
+
directory: "/"
|
|
27
|
+
schedule:
|
|
28
|
+
interval: "weekly"
|
|
29
|
+
day: "sunday"
|
|
30
|
+
time: "09:00"
|
|
31
|
+
timezone: "America/Los_Angeles"
|
|
32
|
+
cooldown:
|
|
33
|
+
default-days: 1
|
|
34
|
+
labels:
|
|
35
|
+
- "dependencies"
|
|
36
|
+
- "github-actions"
|
|
37
|
+
commit-message:
|
|
38
|
+
prefix: "chore(deps)"
|
|
39
|
+
groups:
|
|
40
|
+
actions:
|
|
41
|
+
patterns:
|
|
42
|
+
- "*"
|
|
@@ -8,11 +8,11 @@ jobs:
|
|
|
8
8
|
lint:
|
|
9
9
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
10
10
|
steps:
|
|
11
|
-
- uses: actions/checkout@
|
|
12
|
-
- uses: astral-sh/setup-uv@
|
|
11
|
+
- uses: actions/checkout@v7
|
|
12
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
13
13
|
with:
|
|
14
14
|
enable-cache: true
|
|
15
|
-
- uses: actions/setup-python@
|
|
15
|
+
- uses: actions/setup-python@v7
|
|
16
16
|
with:
|
|
17
17
|
python-version: "3.11"
|
|
18
18
|
- run: uv sync --group dev
|
|
@@ -22,11 +22,11 @@ jobs:
|
|
|
22
22
|
test:
|
|
23
23
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
24
24
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
26
|
-
- uses: astral-sh/setup-uv@
|
|
25
|
+
- uses: actions/checkout@v7
|
|
26
|
+
- uses: astral-sh/setup-uv@v9.0.0
|
|
27
27
|
with:
|
|
28
28
|
enable-cache: true
|
|
29
|
-
- uses: actions/setup-python@
|
|
29
|
+
- uses: actions/setup-python@v7
|
|
30
30
|
with:
|
|
31
31
|
python-version: "3.11"
|
|
32
32
|
- run: uv sync --group dev
|
|
@@ -18,10 +18,10 @@ jobs:
|
|
|
18
18
|
contents: read
|
|
19
19
|
steps:
|
|
20
20
|
- name: Checkout
|
|
21
|
-
uses: actions/checkout@
|
|
21
|
+
uses: actions/checkout@v7
|
|
22
22
|
|
|
23
23
|
- name: Install uv
|
|
24
|
-
uses: astral-sh/setup-uv@
|
|
24
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
25
25
|
with:
|
|
26
26
|
enable-cache: true
|
|
27
27
|
cache-dependency-glob: "uv.lock"
|
|
@@ -57,10 +57,10 @@ jobs:
|
|
|
57
57
|
python-version: ["3.11", "3.12", "3.13"]
|
|
58
58
|
steps:
|
|
59
59
|
- name: Checkout
|
|
60
|
-
uses: actions/checkout@
|
|
60
|
+
uses: actions/checkout@v7
|
|
61
61
|
|
|
62
62
|
- name: Install uv
|
|
63
|
-
uses: astral-sh/setup-uv@
|
|
63
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
64
64
|
with:
|
|
65
65
|
enable-cache: true
|
|
66
66
|
cache-dependency-glob: "uv.lock"
|
|
@@ -88,10 +88,10 @@ jobs:
|
|
|
88
88
|
id-token: write
|
|
89
89
|
steps:
|
|
90
90
|
- name: Checkout
|
|
91
|
-
uses: actions/checkout@
|
|
91
|
+
uses: actions/checkout@v7
|
|
92
92
|
|
|
93
93
|
- name: Install uv
|
|
94
|
-
uses: astral-sh/setup-uv@
|
|
94
|
+
uses: astral-sh/setup-uv@v9.0.0
|
|
95
95
|
|
|
96
96
|
- name: Set up Python
|
|
97
97
|
run: uv python install 3.11
|
|
@@ -200,7 +200,7 @@ jobs:
|
|
|
200
200
|
contents: write
|
|
201
201
|
steps:
|
|
202
202
|
- name: Checkout
|
|
203
|
-
uses: actions/checkout@
|
|
203
|
+
uses: actions/checkout@v7
|
|
204
204
|
with:
|
|
205
205
|
ref: main
|
|
206
206
|
token: ${{ secrets.GH_PAT }}
|
|
@@ -216,7 +216,7 @@ jobs:
|
|
|
216
216
|
git push
|
|
217
217
|
|
|
218
218
|
- name: Create Release
|
|
219
|
-
uses: actions/github-script@
|
|
219
|
+
uses: actions/github-script@v9
|
|
220
220
|
with:
|
|
221
221
|
script: |
|
|
222
222
|
const tag = context.ref.replace('refs/tags/', '');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datalegion-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: CLI for the Data Legion API — agent-friendly, fully async
|
|
5
5
|
Project-URL: Homepage, https://www.datalegion.ai
|
|
6
6
|
Project-URL: Documentation, https://www.datalegion.ai/docs
|
|
@@ -35,7 +35,7 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
|
|
36
36
|
The official command-line interface for the [Data Legion](https://www.datalegion.ai) API. Built for both humans and AI agents.
|
|
37
37
|
|
|
38
|
-
Look up people and companies by email, phone, name, domain, LinkedIn, or ticker symbol. Search
|
|
38
|
+
Look up people and companies by email, phone, name, domain, LinkedIn, or ticker symbol. Search using SQL syntax. Clean, hash, and validate data fields before or after enrichment. Track credit usage and manage your configuration — all from the terminal.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
pip install datalegion-cli
|
|
@@ -159,13 +159,20 @@ datalegion-cli person enrich --email john@example.com --multiple --min-confidenc
|
|
|
159
159
|
datalegion-cli person enrich --email john@example.com --fields "full_name,emails,phones"
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
### Person search
|
|
162
|
+
### Person search (Beta)
|
|
163
163
|
|
|
164
164
|
```bash
|
|
165
165
|
# SQL-based search
|
|
166
166
|
datalegion-cli person search "SELECT * FROM people WHERE company_name ILIKE '%google%' AND state = 'CA'" --limit 5
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
### Person discovery (Beta)
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Natural-language search
|
|
173
|
+
datalegion-cli person discover "software engineers in San Francisco who know Rust" --limit 10
|
|
174
|
+
```
|
|
175
|
+
|
|
169
176
|
### Company enrichment
|
|
170
177
|
|
|
171
178
|
```bash
|
|
@@ -179,13 +186,20 @@ datalegion-cli company enrich --ticker AAPL
|
|
|
179
186
|
datalegion-cli company enrich --name "Stripe" --industry "Financial Services"
|
|
180
187
|
```
|
|
181
188
|
|
|
182
|
-
### Company search
|
|
189
|
+
### Company search (Beta)
|
|
183
190
|
|
|
184
191
|
```bash
|
|
185
192
|
# SQL-based search
|
|
186
193
|
datalegion-cli company search "SELECT * FROM companies WHERE industry ILIKE '%software%' AND legion_employee_count > 100"
|
|
187
194
|
```
|
|
188
195
|
|
|
196
|
+
### Company discovery (Beta)
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Natural-language search
|
|
200
|
+
datalegion-cli company discover "fintech startups in New York with under 50 employees"
|
|
201
|
+
```
|
|
202
|
+
|
|
189
203
|
### Utility commands
|
|
190
204
|
|
|
191
205
|
```bash
|
|
@@ -197,6 +211,10 @@ datalegion-cli utility hash john@example.com
|
|
|
197
211
|
|
|
198
212
|
# Validate fields before enrichment
|
|
199
213
|
datalegion-cli utility validate --email "test@example.com" --phone "+15551234567"
|
|
214
|
+
|
|
215
|
+
# Report a data issue on a record (no credit cost; include --correct or --comment)
|
|
216
|
+
datalegion-cli utility report person --legion-id abc123 --issue-type outdated \
|
|
217
|
+
--issue-level field --field job_title --observed "CTO" --correct "CEO"
|
|
200
218
|
```
|
|
201
219
|
|
|
202
220
|
### Credits
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The official command-line interface for the [Data Legion](https://www.datalegion.ai) API. Built for both humans and AI agents.
|
|
4
4
|
|
|
5
|
-
Look up people and companies by email, phone, name, domain, LinkedIn, or ticker symbol. Search
|
|
5
|
+
Look up people and companies by email, phone, name, domain, LinkedIn, or ticker symbol. Search using SQL syntax. Clean, hash, and validate data fields before or after enrichment. Track credit usage and manage your configuration — all from the terminal.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
pip install datalegion-cli
|
|
@@ -126,13 +126,20 @@ datalegion-cli person enrich --email john@example.com --multiple --min-confidenc
|
|
|
126
126
|
datalegion-cli person enrich --email john@example.com --fields "full_name,emails,phones"
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
### Person search
|
|
129
|
+
### Person search (Beta)
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
132
|
# SQL-based search
|
|
133
133
|
datalegion-cli person search "SELECT * FROM people WHERE company_name ILIKE '%google%' AND state = 'CA'" --limit 5
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
### Person discovery (Beta)
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Natural-language search
|
|
140
|
+
datalegion-cli person discover "software engineers in San Francisco who know Rust" --limit 10
|
|
141
|
+
```
|
|
142
|
+
|
|
136
143
|
### Company enrichment
|
|
137
144
|
|
|
138
145
|
```bash
|
|
@@ -146,13 +153,20 @@ datalegion-cli company enrich --ticker AAPL
|
|
|
146
153
|
datalegion-cli company enrich --name "Stripe" --industry "Financial Services"
|
|
147
154
|
```
|
|
148
155
|
|
|
149
|
-
### Company search
|
|
156
|
+
### Company search (Beta)
|
|
150
157
|
|
|
151
158
|
```bash
|
|
152
159
|
# SQL-based search
|
|
153
160
|
datalegion-cli company search "SELECT * FROM companies WHERE industry ILIKE '%software%' AND legion_employee_count > 100"
|
|
154
161
|
```
|
|
155
162
|
|
|
163
|
+
### Company discovery (Beta)
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Natural-language search
|
|
167
|
+
datalegion-cli company discover "fintech startups in New York with under 50 employees"
|
|
168
|
+
```
|
|
169
|
+
|
|
156
170
|
### Utility commands
|
|
157
171
|
|
|
158
172
|
```bash
|
|
@@ -164,6 +178,10 @@ datalegion-cli utility hash john@example.com
|
|
|
164
178
|
|
|
165
179
|
# Validate fields before enrichment
|
|
166
180
|
datalegion-cli utility validate --email "test@example.com" --phone "+15551234567"
|
|
181
|
+
|
|
182
|
+
# Report a data issue on a record (no credit cost; include --correct or --comment)
|
|
183
|
+
datalegion-cli utility report person --legion-id abc123 --issue-type outdated \
|
|
184
|
+
--issue-level field --field job_title --observed "CTO" --correct "CEO"
|
|
167
185
|
```
|
|
168
186
|
|
|
169
187
|
### Credits
|
|
@@ -111,8 +111,8 @@ class LegionClient:
|
|
|
111
111
|
async def person_search(self, **kwargs: Any) -> dict[str, Any]:
|
|
112
112
|
return await self.request("POST", "/person/search", payload=_strip(kwargs))
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
async def person_discover(self, **kwargs: Any) -> dict[str, Any]:
|
|
115
|
+
return await self.request("POST", "/person/discover", payload=_strip(kwargs))
|
|
116
116
|
|
|
117
117
|
async def person_bulk(self, **kwargs: Any) -> dict[str, Any]:
|
|
118
118
|
return await self.request("POST", "/person/enrich/bulk", payload=_strip(kwargs))
|
|
@@ -123,8 +123,8 @@ class LegionClient:
|
|
|
123
123
|
async def company_search(self, **kwargs: Any) -> dict[str, Any]:
|
|
124
124
|
return await self.request("POST", "/company/search", payload=_strip(kwargs))
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
async def company_discover(self, **kwargs: Any) -> dict[str, Any]:
|
|
127
|
+
return await self.request("POST", "/company/discover", payload=_strip(kwargs))
|
|
128
128
|
|
|
129
129
|
async def company_bulk(self, **kwargs: Any) -> dict[str, Any]:
|
|
130
130
|
return await self.request("POST", "/company/enrich/bulk", payload=_strip(kwargs))
|
|
@@ -138,6 +138,9 @@ class LegionClient:
|
|
|
138
138
|
async def utility_validate(self, **kwargs: Any) -> dict[str, Any]:
|
|
139
139
|
return await self.request("POST", "/utility/validate", payload=_strip(kwargs))
|
|
140
140
|
|
|
141
|
+
async def utility_report(self, kind: str, **kwargs: Any) -> dict[str, Any]:
|
|
142
|
+
return await self.request("POST", f"/utility/report/{kind}", payload=_strip(kwargs))
|
|
143
|
+
|
|
141
144
|
async def credits_balance(self) -> dict[str, Any]:
|
|
142
145
|
return await self.request("GET", "/credits")
|
|
143
146
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Company enrichment and
|
|
1
|
+
"""Company enrichment, search, and discovery commands."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ from datalegion_cli.async_typer import async_command
|
|
|
12
12
|
from datalegion_cli.client import APIError, LegionClient
|
|
13
13
|
from datalegion_cli.output import emit_credits, emit_error, emit_json
|
|
14
14
|
|
|
15
|
-
app = typer.Typer(name="company", help="Company enrichment and
|
|
15
|
+
app = typer.Typer(name="company", help="Company enrichment, search, and discovery.")
|
|
16
16
|
|
|
17
17
|
# ── Shared options ───────────────────────────────────────────────────
|
|
18
18
|
|
|
@@ -110,7 +110,7 @@ async def search(
|
|
|
110
110
|
include_fields: FieldsInclude = None,
|
|
111
111
|
exclude_fields: FieldsExclude = None,
|
|
112
112
|
) -> None:
|
|
113
|
-
"""Search for companies using SQL WHERE syntax.
|
|
113
|
+
"""Search for companies using SQL WHERE syntax (Beta).
|
|
114
114
|
|
|
115
115
|
Examples:
|
|
116
116
|
datalegion-cli company search "industry = 'Software' AND employee_count > 100"
|
|
@@ -135,30 +135,32 @@ async def search(
|
|
|
135
135
|
await client.close()
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
138
|
+
@app.command()
|
|
139
|
+
@async_command
|
|
140
|
+
async def discover(
|
|
141
|
+
query: Annotated[str, typer.Argument(help="Natural language company search query.")],
|
|
142
|
+
limit: LimitOpt = 10,
|
|
143
|
+
titlecase: TitleOpt = False,
|
|
144
|
+
include_fields: FieldsInclude = None,
|
|
145
|
+
exclude_fields: FieldsExclude = None,
|
|
146
|
+
) -> None:
|
|
147
|
+
"""Search for companies using natural language (Beta)."""
|
|
148
|
+
client = LegionClient()
|
|
149
|
+
try:
|
|
150
|
+
result = await client.company_discover(
|
|
151
|
+
query=query,
|
|
152
|
+
limit=limit,
|
|
153
|
+
titlecase=titlecase,
|
|
154
|
+
include_fields=include_fields,
|
|
155
|
+
exclude_fields=exclude_fields,
|
|
156
|
+
)
|
|
157
|
+
emit_json(result)
|
|
158
|
+
emit_credits(client.last_credits_used, client.last_credits_remaining)
|
|
159
|
+
except APIError as e:
|
|
160
|
+
emit_error(e.message, code=e.error, details=e.details, as_json=True)
|
|
161
|
+
raise typer.Exit(1) from e
|
|
162
|
+
finally:
|
|
163
|
+
await client.close()
|
|
162
164
|
|
|
163
165
|
|
|
164
166
|
# TODO: Uncomment when bulk enrichment is ready
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Person enrichment and
|
|
1
|
+
"""Person enrichment, search, and discovery commands."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ from datalegion_cli.async_typer import async_command
|
|
|
12
12
|
from datalegion_cli.client import APIError, LegionClient
|
|
13
13
|
from datalegion_cli.output import emit_credits, emit_error, emit_json
|
|
14
14
|
|
|
15
|
-
app = typer.Typer(name="person", help="Person enrichment and
|
|
15
|
+
app = typer.Typer(name="person", help="Person enrichment, search, and discovery.")
|
|
16
16
|
|
|
17
17
|
# ── Shared options ───────────────────────────────────────────────────
|
|
18
18
|
|
|
@@ -136,7 +136,7 @@ async def search(
|
|
|
136
136
|
include_fields: FieldsInclude = None,
|
|
137
137
|
exclude_fields: FieldsExclude = None,
|
|
138
138
|
) -> None:
|
|
139
|
-
"""Search for people using SQL WHERE syntax.
|
|
139
|
+
"""Search for people using SQL WHERE syntax (Beta).
|
|
140
140
|
|
|
141
141
|
Examples:
|
|
142
142
|
datalegion-cli person search "job_title = 'CEO' AND company = 'Acme Corp'"
|
|
@@ -161,30 +161,32 @@ async def search(
|
|
|
161
161
|
await client.close()
|
|
162
162
|
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
164
|
+
@app.command()
|
|
165
|
+
@async_command
|
|
166
|
+
async def discover(
|
|
167
|
+
query: Annotated[str, typer.Argument(help="Natural language search query.")],
|
|
168
|
+
limit: LimitOpt = 10,
|
|
169
|
+
titlecase: TitleOpt = False,
|
|
170
|
+
include_fields: FieldsInclude = None,
|
|
171
|
+
exclude_fields: FieldsExclude = None,
|
|
172
|
+
) -> None:
|
|
173
|
+
"""Search for people using natural language (Beta)."""
|
|
174
|
+
client = LegionClient()
|
|
175
|
+
try:
|
|
176
|
+
result = await client.person_discover(
|
|
177
|
+
query=query,
|
|
178
|
+
limit=limit,
|
|
179
|
+
titlecase=titlecase,
|
|
180
|
+
include_fields=include_fields,
|
|
181
|
+
exclude_fields=exclude_fields,
|
|
182
|
+
)
|
|
183
|
+
emit_json(result)
|
|
184
|
+
emit_credits(client.last_credits_used, client.last_credits_remaining)
|
|
185
|
+
except APIError as e:
|
|
186
|
+
emit_error(e.message, code=e.error, details=e.details, as_json=True)
|
|
187
|
+
raise typer.Exit(1) from e
|
|
188
|
+
finally:
|
|
189
|
+
await client.close()
|
|
188
190
|
|
|
189
191
|
|
|
190
192
|
# TODO: Uncomment when bulk enrichment is ready
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Utility commands — clean, hash, validate."""
|
|
1
|
+
"""Utility commands — clean, hash, validate, report."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ from datalegion_cli.async_typer import async_command
|
|
|
12
12
|
from datalegion_cli.client import APIError, LegionClient
|
|
13
13
|
from datalegion_cli.output import emit_error, emit_json
|
|
14
14
|
|
|
15
|
-
app = typer.Typer(name="utility", help="Data cleaning, hashing, and
|
|
15
|
+
app = typer.Typer(name="utility", help="Data cleaning, hashing, validation, and issue reporting.")
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@app.command()
|
|
@@ -120,3 +120,69 @@ async def validate(
|
|
|
120
120
|
raise typer.Exit(1) from e
|
|
121
121
|
finally:
|
|
122
122
|
await client.close()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@app.command()
|
|
126
|
+
@async_command
|
|
127
|
+
async def report(
|
|
128
|
+
kind: Annotated[str, typer.Argument(help="Record type: person or company.")],
|
|
129
|
+
legion_id: Annotated[str, typer.Option("--legion-id", help="Legion ID of the record.")],
|
|
130
|
+
issue_type: Annotated[
|
|
131
|
+
str,
|
|
132
|
+
typer.Option(
|
|
133
|
+
"--issue-type",
|
|
134
|
+
help=(
|
|
135
|
+
"Issue type: incorrect, outdated, misattributed, frankenstein, "
|
|
136
|
+
"not_a_real_person (person only), or duplicate."
|
|
137
|
+
),
|
|
138
|
+
),
|
|
139
|
+
],
|
|
140
|
+
issue_level: Annotated[
|
|
141
|
+
str,
|
|
142
|
+
typer.Option("--issue-level", help="Issue level: record, group, or field."),
|
|
143
|
+
] = "record",
|
|
144
|
+
field: Annotated[
|
|
145
|
+
str | None,
|
|
146
|
+
typer.Option("--field", help="Group or field name (for group/field level issues)."),
|
|
147
|
+
] = None,
|
|
148
|
+
observed_value: Annotated[
|
|
149
|
+
str | None, typer.Option("--observed", help="The incorrect value you observed.")
|
|
150
|
+
] = None,
|
|
151
|
+
correct_value: Annotated[
|
|
152
|
+
str | None, typer.Option("--correct", help="The correct value, if known.")
|
|
153
|
+
] = None,
|
|
154
|
+
comment: Annotated[
|
|
155
|
+
str | None, typer.Option("--comment", help="Free-form description of the issue.")
|
|
156
|
+
] = None,
|
|
157
|
+
) -> None:
|
|
158
|
+
"""Report a data issue on a person or company record (no credit cost).
|
|
159
|
+
|
|
160
|
+
Include at least one of --correct or --comment.
|
|
161
|
+
|
|
162
|
+
Examples:
|
|
163
|
+
datalegion-cli utility report person --legion-id abc123 --issue-type outdated \\
|
|
164
|
+
--issue-level field --field job_title --observed "CTO" --correct "CEO"
|
|
165
|
+
datalegion-cli utility report company --legion-id xyz789 --issue-type duplicate \\
|
|
166
|
+
--comment "Same company as legion_id def456"
|
|
167
|
+
"""
|
|
168
|
+
if kind not in ("person", "company"):
|
|
169
|
+
raise typer.BadParameter("kind must be 'person' or 'company'.")
|
|
170
|
+
|
|
171
|
+
client = LegionClient()
|
|
172
|
+
try:
|
|
173
|
+
result = await client.utility_report(
|
|
174
|
+
kind,
|
|
175
|
+
legion_id=legion_id,
|
|
176
|
+
issue_type=issue_type,
|
|
177
|
+
issue_level=issue_level,
|
|
178
|
+
field=field,
|
|
179
|
+
observed_value=observed_value,
|
|
180
|
+
correct_value=correct_value,
|
|
181
|
+
comment=comment,
|
|
182
|
+
)
|
|
183
|
+
emit_json(result)
|
|
184
|
+
except APIError as e:
|
|
185
|
+
emit_error(e.message, code=e.error, details=e.details, as_json=True)
|
|
186
|
+
raise typer.Exit(1) from e
|
|
187
|
+
finally:
|
|
188
|
+
await client.close()
|