diffbot 2.0.0__tar.gz → 3.1.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.
Files changed (43) hide show
  1. diffbot-3.1.0/.gitignore +11 -0
  2. diffbot-3.1.0/LICENSE +21 -0
  3. diffbot-3.1.0/PKG-INFO +423 -0
  4. diffbot-3.1.0/README.md +387 -0
  5. diffbot-3.1.0/pyproject.toml +79 -0
  6. diffbot-3.1.0/src/diffbot/__init__.py +63 -0
  7. diffbot-3.1.0/src/diffbot/_auth.py +41 -0
  8. diffbot-3.1.0/src/diffbot/ask.py +195 -0
  9. diffbot-3.1.0/src/diffbot/cli/__init__.py +431 -0
  10. diffbot-3.1.0/src/diffbot/cli/__main__.py +4 -0
  11. diffbot-3.1.0/src/diffbot/cli/_common.py +21 -0
  12. diffbot-3.1.0/src/diffbot/cli/dql.py +310 -0
  13. diffbot-3.1.0/src/diffbot/cli/entities.py +155 -0
  14. diffbot-3.1.0/src/diffbot/cli/ontology.py +74 -0
  15. diffbot-3.1.0/src/diffbot/client.py +388 -0
  16. diffbot-3.1.0/src/diffbot/crawl.py +270 -0
  17. diffbot-3.1.0/src/diffbot/errors.py +51 -0
  18. diffbot-3.1.0/src/diffbot/extract.py +45 -0
  19. diffbot-3.1.0/src/diffbot/kg.py +128 -0
  20. diffbot-3.1.0/src/diffbot/nlp.py +37 -0
  21. diffbot-3.1.0/src/diffbot/ontology.py +160 -0
  22. diffbot-3.1.0/src/diffbot/web_search.py +56 -0
  23. diffbot-3.1.0/tests/conftest.py +16 -0
  24. diffbot-3.1.0/tests/test_ask.py +274 -0
  25. diffbot-3.1.0/tests/test_async.py +94 -0
  26. diffbot-3.1.0/tests/test_crawl.py +63 -0
  27. diffbot-3.1.0/tests/test_dql.py +100 -0
  28. diffbot-3.1.0/tests/test_dql_cli.py +118 -0
  29. diffbot-3.1.0/tests/test_extract.py +170 -0
  30. diffbot-3.1.0/tests/test_ontology.py +119 -0
  31. diffbot-3.1.0/tests/test_readme_examples.py +290 -0
  32. diffbot-3.1.0/tests/test_web_search.py +51 -0
  33. diffbot-2.0.0/PKG-INFO +0 -120
  34. diffbot-2.0.0/README.rst +0 -99
  35. diffbot-2.0.0/diffbot.egg-info/PKG-INFO +0 -120
  36. diffbot-2.0.0/diffbot.egg-info/SOURCES.txt +0 -10
  37. diffbot-2.0.0/diffbot.egg-info/dependency_links.txt +0 -1
  38. diffbot-2.0.0/diffbot.egg-info/entry_points.txt +0 -3
  39. diffbot-2.0.0/diffbot.egg-info/top_level.txt +0 -1
  40. diffbot-2.0.0/diffbot.egg-info/zip-safe +0 -1
  41. diffbot-2.0.0/diffbot.py +0 -273
  42. diffbot-2.0.0/setup.cfg +0 -13
  43. diffbot-2.0.0/setup.py +0 -54
@@ -0,0 +1,11 @@
1
+ # Python
2
+ .venv
3
+ __pycache__
4
+ .pytest_cache
5
+ .env
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+
10
+ # Claude
11
+ .claude/settings.local.json
diffbot-3.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Diffbot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
diffbot-3.1.0/PKG-INFO ADDED
@@ -0,0 +1,423 @@
1
+ Metadata-Version: 2.5
2
+ Name: diffbot
3
+ Version: 3.1.0
4
+ Summary: Python client library for Diffbot APIs
5
+ Project-URL: Homepage, https://github.com/diffbot/diffbot-python
6
+ Project-URL: Documentation, https://github.com/diffbot/diffbot-python#readme
7
+ Project-URL: Repository, https://github.com/diffbot/diffbot-python
8
+ Project-URL: Issues, https://github.com/diffbot/diffbot-python/issues
9
+ Author-email: Jerome Choo <jerome@diffbot.com>, Mike Tung <miket@diffbot.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api-client,crawler,diffbot,extract,knowledge-graph,llm,nlp,web-scraping
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Internet :: WWW/HTTP
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
25
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Topic :: Text Processing :: Markup :: HTML
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.9
30
+ Requires-Dist: click>=8.1.0
31
+ Requires-Dist: httpx>=0.27.0
32
+ Requires-Dist: rich>=13.0.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Diffbot Python Library
38
+
39
+ > ⚠️ **The PyPI package is now [`diffbot`](https://pypi.org/project/diffbot/)** (`pip install diffbot`).
40
+ > `diffbot-python` is legacy and its final release (0.3.0) will never be updated.
41
+ > See [Installation](#installation) to migrate.
42
+
43
+ Python client library for [Diffbot](https://www.diffbot.com) APIs.
44
+
45
+
46
+ ## Installation
47
+
48
+ Install the [standalone CLI binary](#standalone-binary) for [agentic use](#how-to-use-with-an-agent):
49
+
50
+ ```bash
51
+ curl -fsSL https://raw.githubusercontent.com/diffbot/diffbot-python/main/install.sh | sh
52
+ ```
53
+
54
+ If you prefer, the full Python library can also be installed with pip:
55
+
56
+ ```bash
57
+ python3 -m pip install diffbot
58
+ ```
59
+
60
+ > This package was formerly published as `diffbot-python`, whose final release (0.3.0) gets no further updates.
61
+ > If you're upgrading from it, run `pip uninstall diffbot-python && pip install --force-reinstall diffbot`
62
+ > and replace `diffbot-python` with `diffbot` in your requirements.
63
+
64
+ For local development:
65
+
66
+ ```bash
67
+ pip install -e ".[dev]"
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ### Authentication
73
+
74
+ The CLI and the library can share a single credential. The token always has to be
75
+ passed to the client explicitly, but `resolve_token()` gives you the same lookup the
76
+ CLI uses, in this order:
77
+
78
+ 1. An explicit token passed to `resolve_token(token)`.
79
+ 2. The `DIFFBOT_API_TOKEN` environment variable.
80
+ 3. A `DIFFBOT_API_TOKEN=...` line in `~/.diffbot/credentials`.
81
+
82
+ Set it once and it works for both the CLI and your scripts. Either export it:
83
+
84
+ ```bash
85
+ export DIFFBOT_API_TOKEN=<TOKEN>
86
+ ```
87
+
88
+ …or write it to the shared credentials file (handy for keeping it out of your shell environment):
89
+
90
+ ```bash
91
+ mkdir -p ~/.diffbot
92
+ printf 'DIFFBOT_API_TOKEN=%s\n' '<TOKEN>' > ~/.diffbot/credentials
93
+ chmod 600 ~/.diffbot/credentials
94
+ ```
95
+
96
+ With either in place, resolve the token and pass it to the client:
97
+
98
+ ```python
99
+ from diffbot import Diffbot, resolve_token
100
+
101
+ db = Diffbot(token=resolve_token()) # from env var or ~/.diffbot/credentials
102
+ data = db.extract("https://www.example.com")
103
+ ```
104
+
105
+ ### Client configuration
106
+
107
+ `Diffbot` and `DiffbotAsync` take the same keyword arguments — the client is the single
108
+ place to configure the SDK.
109
+
110
+ | Argument | Default | Used by |
111
+ |----------|---------|---------|
112
+ | `token` | — (required) | all |
113
+ | `timeout` | `30.0` (seconds) | all |
114
+ | `transport` | httpx default | all |
115
+ | `analyze_url` | `https://api.diffbot.com/v3` | `extract` |
116
+ | `crawler_url` | `https://api.diffbot.com/v3/crawl` | `crawl`, `crawl_list_jobs`, `crawl_get_job`, `crawl_delete_job` |
117
+ | `llm_url` | `https://llm.diffbot.com/rag/v1/chat/completions` | `ask`, `ask_json` |
118
+ | `web_search_url` | `https://llm.diffbot.com/api/v1/web_search` | `web_search` |
119
+ | `nlp_url` | `https://nl.diffbot.com/v1/` | `entities` |
120
+ | `dql_url` | `https://kg.diffbot.com/kg/v3/dql` | `dql`, `dql_parallel` |
121
+ | `ontology_url` | `https://kg.diffbot.com/kg/ontology` | `dql_fetch_ontology`, `dql_refresh_ontology` |
122
+
123
+ ```python
124
+ from diffbot import Diffbot
125
+
126
+ db = Diffbot(
127
+ token="YOUR_TOKEN",
128
+ timeout=60.0,
129
+ dql_url="http://localhost:8080/kg/v3/dql",
130
+ )
131
+ ```
132
+
133
+ `analyze_url` is a base the SDK appends `/{api}` to, and `crawler_url` is used as given
134
+ for job management and with `/data` appended for crawl results. The rest are complete
135
+ endpoints, used as given.
136
+
137
+ Passing `transport` replaces the httpx transport, which is the hook for retries, proxies,
138
+ or mocking in tests. `Diffbot` takes an `httpx.BaseTransport`, `DiffbotAsync` an
139
+ `httpx.AsyncBaseTransport`:
140
+
141
+ ```python
142
+ import httpx
143
+ from diffbot import Diffbot
144
+
145
+ db = Diffbot(token="YOUR_TOKEN", transport=httpx.HTTPTransport(retries=3))
146
+ ```
147
+
148
+ ### Extract structured content
149
+ ```python
150
+ from diffbot import Diffbot
151
+
152
+ db = Diffbot(token="YOUR_TOKEN")
153
+ data = db.extract("https://www.example.com")
154
+ ```
155
+
156
+ ### Ask Diffbot LLM
157
+ ```python
158
+ from diffbot import Diffbot
159
+
160
+ db = Diffbot(token="YOUR_TOKEN")
161
+ for chunk in db.ask([{"role": "user", "content": "What's the capital of France?"}]):
162
+ print(chunk, end="")
163
+ ```
164
+
165
+ ### Structured output
166
+ Pass a JSON Schema to constrain the answer. The model is held to the schema by a grammar during decoding, so the result parses reliably even though the answer is retrieved live from the web.
167
+
168
+ ```python
169
+ from diffbot import Diffbot
170
+
171
+ db = Diffbot(token="YOUR_TOKEN")
172
+ schema = {
173
+ "type": "object",
174
+ "properties": {
175
+ "country": {"type": "string"},
176
+ "capital": {"type": "string"},
177
+ },
178
+ "required": ["country", "capital"],
179
+ }
180
+ answer = db.ask_json([{"role": "user", "content": "What's the capital of France?"}], schema)
181
+ print(answer["capital"])
182
+ ```
183
+
184
+ Omit the schema to let the model choose the shape, or use `ask` with `response_format` to stream a constrained answer:
185
+
186
+ ```python
187
+ from diffbot import Diffbot, json_schema_format
188
+
189
+ db = Diffbot(token="YOUR_TOKEN")
190
+ answer = db.ask_json([{"role": "user", "content": "What's the capital of France?"}])
191
+
192
+ for chunk in db.ask(
193
+ [{"role": "user", "content": "What's the capital of France?"}],
194
+ response_format=json_schema_format(schema),
195
+ ):
196
+ print(chunk, end="")
197
+ ```
198
+
199
+ > **Avoid `response_format={"type": "json_object"}`.** The endpoint accepts it, but applies no grammar to it — the RAG loop's internal tool call is itself a JSON object, so it can be returned as the final answer. This is reproducible whenever the request includes a system message. `ask_json` therefore defaults to a permissive JSON Schema instead, and raises `ValidationError` if it ever sees a tool call come back.
200
+
201
+ ### Crawl a site for structured content
202
+ ```python
203
+ from diffbot import Diffbot
204
+
205
+ db = Diffbot(token="YOUR_TOKEN")
206
+ for event in db.crawl("https://www.example.com", hops=1):
207
+ print(event)
208
+ ```
209
+
210
+ ### Query the Knowledge Graph
211
+ ```python
212
+ from diffbot import Diffbot
213
+
214
+ db = Diffbot(token="YOUR_TOKEN")
215
+ results = db.dql('type:Organization name:"Diffbot"')
216
+ ```
217
+
218
+ ### Web Search
219
+ ```python
220
+ from diffbot import Diffbot
221
+
222
+ db = Diffbot(token="YOUR_TOKEN")
223
+ results = db.web_search("diffbot knowledge graph")
224
+ for r in results["search_results"]:
225
+ print(r["score"], r["title"], r["pageUrl"])
226
+ print(r["content"])
227
+
228
+ # snippet_length controls how much of each page comes back in "content":
229
+ # "short" (~1-1.5 KB per result), "medium", "long" (default), or "full"
230
+ results = db.web_search("diffbot knowledge graph", num_results=5, snippet_length="short")
231
+
232
+ # "full" with a url: query returns the whole stored page
233
+ page = db.web_search("url:https://en.wikipedia.org/wiki/Knowledge_graph", snippet_length="full")
234
+ ```
235
+
236
+ ### Entities (NLP)
237
+ ```python
238
+ from diffbot import Diffbot
239
+
240
+ db = Diffbot(token="YOUR_TOKEN")
241
+ result = db.entities("Apple CEO Tim Cook announced record quarterly earnings.")
242
+ for entity in result["entities"]:
243
+ print(entity["name"], entity.get("type"), entity.get("id"))
244
+ print("sentiment:", result.get("sentiment"))
245
+ ```
246
+
247
+ ## Async Usage
248
+
249
+ ### Extract structured content
250
+ ```python
251
+ import asyncio
252
+ from diffbot import DiffbotAsync
253
+
254
+ async def main():
255
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
256
+ data = await db.extract("https://www.example.com")
257
+ print(data)
258
+
259
+ asyncio.run(main())
260
+ ```
261
+
262
+ ### Ask Diffbot LLM
263
+ ```python
264
+ import asyncio
265
+ from diffbot import DiffbotAsync
266
+
267
+ async def main():
268
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
269
+ async for chunk in db.ask([{"role": "user", "content": "What's the capital of France?"}]):
270
+ print(chunk, end="")
271
+
272
+ asyncio.run(main())
273
+ ```
274
+
275
+ ### Structured output
276
+ ```python
277
+ import asyncio
278
+ from diffbot import DiffbotAsync
279
+
280
+ schema = {
281
+ "type": "object",
282
+ "properties": {
283
+ "country": {"type": "string"},
284
+ "capital": {"type": "string"},
285
+ },
286
+ "required": ["country", "capital"],
287
+ }
288
+
289
+ async def main():
290
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
291
+ answer = await db.ask_json(
292
+ [{"role": "user", "content": "What's the capital of France?"}], schema
293
+ )
294
+ print(answer["capital"])
295
+
296
+ asyncio.run(main())
297
+ ```
298
+
299
+ ### Crawl a site for structured content
300
+ ```python
301
+ import asyncio
302
+ from diffbot import DiffbotAsync
303
+
304
+ async def main():
305
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
306
+ async for event in db.crawl("https://www.example.com", hops=1):
307
+ print(event)
308
+
309
+ asyncio.run(main())
310
+ ```
311
+
312
+ ### Query the Knowledge Graph
313
+ ```python
314
+ import asyncio
315
+ from diffbot import DiffbotAsync
316
+
317
+ async def main():
318
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
319
+ results = await db.dql('type:Organization name:"Diffbot"')
320
+ print(results)
321
+
322
+ asyncio.run(main())
323
+ ```
324
+
325
+ ### Web Search
326
+ ```python
327
+ import asyncio
328
+ from diffbot import DiffbotAsync
329
+
330
+ async def main():
331
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
332
+ results = await db.web_search("diffbot knowledge graph")
333
+ for r in results["search_results"]:
334
+ print(r["score"], r["title"], r["pageUrl"])
335
+ print(r["content"])
336
+
337
+ asyncio.run(main())
338
+ ```
339
+
340
+ ### Entities (NLP)
341
+ ```python
342
+ import asyncio
343
+ from diffbot import DiffbotAsync
344
+
345
+ async def main():
346
+ async with DiffbotAsync(token="YOUR_TOKEN") as db:
347
+ result = await db.entities("Apple CEO Tim Cook announced record quarterly earnings.")
348
+ for entity in result["entities"]:
349
+ print(entity["name"], entity.get("type"), entity.get("id"))
350
+ print("sentiment:", result.get("sentiment"))
351
+
352
+ asyncio.run(main())
353
+ ```
354
+
355
+ ## CLI
356
+
357
+ This library also includes a CLI exposed as the `db` command.
358
+
359
+ To make `db` available from anywhere, install it as an isolated tool with [uv](https://docs.astral.sh/uv/):
360
+
361
+ ```bash
362
+ uv tool install .
363
+ ```
364
+
365
+ This drops a `db` executable into `~/.local/bin` (ensure it is on your `PATH`). Use `--force` to reinstall or upgrade after changes, or `--editable` to have source edits take effect immediately. Alternatively, a plain `pip install .` (or `pip install -e .`) also installs the `db` entry point into the active environment.
366
+
367
+ ### Standalone binary
368
+
369
+ Every release also ships a self-contained `db` binary for Linux (x86_64 and aarch64) and macOS (Apple Silicon) as a Python-free option. The installer detects your platform, verifies the SHA256 checksum, and installs (or upgrades) `db` into `~/.local/bin`:
370
+
371
+ ```bash
372
+ curl -fsSL https://raw.githubusercontent.com/diffbot/diffbot-python/main/install.sh | sh
373
+ ```
374
+
375
+ Pin a specific release or install location with flags (or the `DB_VERSION` / `DB_INSTALL_DIR` environment variables); re-running the installer upgrades an existing install in place:
376
+
377
+ ```bash
378
+ curl -fsSL https://raw.githubusercontent.com/diffbot/diffbot-python/main/install.sh | sh -s -- --version v0.2.1 --bin-dir ~/bin
379
+ ```
380
+
381
+ ### How to use
382
+
383
+ ```bash
384
+ export DIFFBOT_API_TOKEN=your-token-here
385
+
386
+ db extract https://www.example.com
387
+ db ask "What's the capital of France?"
388
+ db ask "What's the capital of France?" --json
389
+ db ask "What's the capital of France?" --schema capital.json
390
+ db crawl https://www.example.com --hops 1
391
+ db crawl-list-jobs
392
+ db crawl-delete-job crawl-1234567890
393
+ db web-search "diffbot knowledge graph"
394
+ db web-search "diffbot knowledge graph" -n 5 -f json
395
+ db web-search "diffbot knowledge graph" -n 5 -s short
396
+ db web-search "url:https://en.wikipedia.org/wiki/Knowledge_graph" -s full -f json
397
+ db entities "Apple CEO Tim Cook announced record quarterly earnings."
398
+ db entities "Apple CEO Tim Cook announced record quarterly earnings." -f dql
399
+ ```
400
+
401
+ ### How to use with an agent
402
+ Once installed, this library will work alongside [`diffbot-skills`](https://github.com/diffbot/diffbot-skills) to enable your agent full access to structuring web knowledge with Diffbot. Diffbot Agent Skills even unlocks some additional skills like crafting DQL from natural language.
403
+
404
+ `diffbot-skills` will pick up or install this library automatically.
405
+
406
+
407
+ ## Tests
408
+
409
+ Run the mock test suite:
410
+ ```bash
411
+ python -m pytest
412
+ ```
413
+
414
+ Run live integration tests against the real API (requires a valid token).
415
+ The token is resolved the same way as everywhere else — the `DIFFBOT_API_TOKEN`
416
+ environment variable or `~/.diffbot/credentials`:
417
+ ```bash
418
+ DIFFBOT_API_TOKEN=your_token python -m pytest -m live
419
+ ```
420
+
421
+ ## Acknowledgements
422
+
423
+ Thanks to [@attilaolah](https://github.com/attilaolah), who published the original `diffbot` package in 2012 and looked after the name for 14 years.