exa-py 1.14.4__tar.gz → 1.14.6__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.

Potentially problematic release.


This version of exa-py might be problematic. Click here for more details.

Files changed (38) hide show
  1. {exa_py-1.14.4 → exa_py-1.14.6}/PKG-INFO +17 -13
  2. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/api.py +27 -1
  3. exa_py-1.14.6/exa_py/websets/_generator/pydantic/BaseModel.jinja2 +42 -0
  4. {exa_py-1.14.4 → exa_py-1.14.6}/pyproject.toml +2 -10
  5. exa_py-1.14.4/exa_py.egg-info/PKG-INFO +0 -129
  6. exa_py-1.14.4/exa_py.egg-info/SOURCES.txt +0 -35
  7. exa_py-1.14.4/exa_py.egg-info/dependency_links.txt +0 -1
  8. exa_py-1.14.4/exa_py.egg-info/requires.txt +0 -6
  9. exa_py-1.14.4/exa_py.egg-info/top_level.txt +0 -1
  10. exa_py-1.14.4/setup.cfg +0 -4
  11. exa_py-1.14.4/setup.py +0 -26
  12. exa_py-1.14.4/tests/test_monitors.py +0 -502
  13. exa_py-1.14.4/tests/test_search_api.py +0 -107
  14. exa_py-1.14.4/tests/test_websets.py +0 -418
  15. {exa_py-1.14.4 → exa_py-1.14.6}/README.md +0 -0
  16. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/__init__.py +0 -0
  17. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/py.typed +0 -0
  18. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/research/__init__.py +0 -0
  19. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/research/client.py +0 -0
  20. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/research/models.py +0 -0
  21. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/utils.py +0 -0
  22. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/__init__.py +0 -0
  23. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/client.py +0 -0
  24. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/core/__init__.py +0 -0
  25. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/core/base.py +0 -0
  26. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/enrichments/__init__.py +0 -0
  27. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/enrichments/client.py +0 -0
  28. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/items/__init__.py +0 -0
  29. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/items/client.py +0 -0
  30. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/monitors/__init__.py +0 -0
  31. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/monitors/client.py +0 -0
  32. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/monitors/runs/__init__.py +0 -0
  33. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/monitors/runs/client.py +0 -0
  34. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/searches/__init__.py +0 -0
  35. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/searches/client.py +0 -0
  36. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/types.py +0 -0
  37. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/webhooks/__init__.py +0 -0
  38. {exa_py-1.14.4 → exa_py-1.14.6}/exa_py/websets/webhooks/client.py +0 -0
@@ -1,21 +1,24 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: exa-py
3
- Version: 1.14.4
3
+ Version: 1.14.6
4
4
  Summary: Python SDK for Exa API.
5
- Home-page: https://github.com/exa-labs/exa-py
6
- Author: Exa
7
- Author-email: Exa AI <hello@exa.ai>
8
5
  License: MIT
6
+ Author: Exa AI
7
+ Author-email: hello@exa.ai
9
8
  Requires-Python: >=3.9
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: httpx (>=0.28.1)
17
+ Requires-Dist: openai (>=1.48)
18
+ Requires-Dist: pydantic (>=2.10.6)
19
+ Requires-Dist: requests (>=2.32.3)
20
+ Requires-Dist: typing-extensions (>=4.12.2)
10
21
  Description-Content-Type: text/markdown
11
- Requires-Dist: requests>=2.32.3
12
- Requires-Dist: typing-extensions>=4.12.2
13
- Requires-Dist: openai>=1.48
14
- Requires-Dist: pydantic>=2.10.6
15
- Requires-Dist: pytest-mock>=3.14.0
16
- Requires-Dist: httpx>=0.28.1
17
- Dynamic: author
18
- Dynamic: home-page
19
22
 
20
23
  # Exa
21
24
 
@@ -127,3 +130,4 @@ exa = Exa(api_key="your-api-key")
127
130
  output_schema=OUTPUT_SCHEMA,
128
131
  )
129
132
  ```
133
+
@@ -166,6 +166,7 @@ CONTENTS_OPTIONS_TYPES = {
166
166
  "text": [dict, bool],
167
167
  "highlights": [dict, bool],
168
168
  "summary": [dict, bool],
169
+ "context": [dict, bool],
169
170
  "metadata": [dict, bool],
170
171
  "livecrawl_timeout": [int],
171
172
  "livecrawl": [LIVECRAWL_OPTIONS],
@@ -292,6 +293,16 @@ class SummaryContentsOptions(TypedDict, total=False):
292
293
  schema: JSONSchema
293
294
 
294
295
 
296
+ class ContextContentsOptions(TypedDict, total=False):
297
+ """Options for retrieving aggregated context from a set of search results.
298
+
299
+ Attributes:
300
+ max_characters (int): The maximum number of characters to include in the context string.
301
+ """
302
+
303
+ max_characters: int
304
+
305
+
295
306
  class ExtrasOptions(TypedDict, total=False):
296
307
  """A class representing additional extraction fields (e.g. links, images)"""
297
308
 
@@ -807,17 +818,23 @@ class SearchResponse(Generic[T]):
807
818
  autoprompt_string (str, optional): The Exa query created by autoprompt.
808
819
  resolved_search_type (str, optional): 'neural' or 'keyword' if auto.
809
820
  auto_date (str, optional): A date for filtering if autoprompt found one.
821
+ context (str, optional): Combined context string when requested via contents.context.
822
+ statuses (List[ContentStatus], optional): Status list from get_contents.
823
+ cost_dollars (CostDollars, optional): Cost breakdown.
810
824
  """
811
825
 
812
826
  results: List[T]
813
827
  autoprompt_string: Optional[str]
814
828
  resolved_search_type: Optional[str]
815
829
  auto_date: Optional[str]
830
+ context: Optional[str] = None
816
831
  statuses: Optional[List[ContentStatus]] = None
817
832
  cost_dollars: Optional[CostDollars] = None
818
833
 
819
834
  def __str__(self):
820
835
  output = "\n\n".join(str(result) for result in self.results)
836
+ if self.context:
837
+ output += f"\nContext: {self.context}"
821
838
  if self.autoprompt_string:
822
839
  output += f"\n\nAutoprompt String: {self.autoprompt_string}"
823
840
  if self.resolved_search_type:
@@ -1254,6 +1271,7 @@ class Exa:
1254
1271
  "text",
1255
1272
  "highlights",
1256
1273
  "summary",
1274
+ "context",
1257
1275
  "subpages",
1258
1276
  "subpage_target",
1259
1277
  "livecrawl",
@@ -1270,6 +1288,7 @@ class Exa:
1270
1288
  data["autopromptString"] if "autopromptString" in data else None,
1271
1289
  data["resolvedSearchType"] if "resolvedSearchType" in data else None,
1272
1290
  data["autoDate"] if "autoDate" in data else None,
1291
+ context=data.get("context"),
1273
1292
  cost_dollars=cost_dollars,
1274
1293
  )
1275
1294
 
@@ -1414,7 +1433,6 @@ class Exa:
1414
1433
  options,
1415
1434
  {**CONTENTS_OPTIONS_TYPES, **CONTENTS_ENDPOINT_OPTIONS_TYPES},
1416
1435
  )
1417
-
1418
1436
  options = to_camel_case(options)
1419
1437
  data = self.request("/contents", options)
1420
1438
  cost_dollars = parse_cost_dollars(data.get("costDollars"))
@@ -1424,6 +1442,7 @@ class Exa:
1424
1442
  data.get("autopromptString"),
1425
1443
  data.get("resolvedSearchType"),
1426
1444
  data.get("autoDate"),
1445
+ context=data.get("context"),
1427
1446
  cost_dollars=cost_dollars,
1428
1447
  statuses=statuses,
1429
1448
  )
@@ -1715,6 +1734,7 @@ class Exa:
1715
1734
  "text",
1716
1735
  "highlights",
1717
1736
  "summary",
1737
+ "context",
1718
1738
  "subpages",
1719
1739
  "subpage_target",
1720
1740
  "livecrawl",
@@ -1731,6 +1751,7 @@ class Exa:
1731
1751
  data.get("autopromptString"),
1732
1752
  data.get("resolvedSearchType"),
1733
1753
  data.get("autoDate"),
1754
+ context=data.get("context"),
1734
1755
  cost_dollars=cost_dollars,
1735
1756
  )
1736
1757
 
@@ -2067,6 +2088,7 @@ class AsyncExa(Exa):
2067
2088
  "text",
2068
2089
  "highlights",
2069
2090
  "summary",
2091
+ "context",
2070
2092
  "subpages",
2071
2093
  "subpage_target",
2072
2094
  "livecrawl",
@@ -2083,6 +2105,7 @@ class AsyncExa(Exa):
2083
2105
  data["autopromptString"] if "autopromptString" in data else None,
2084
2106
  data["resolvedSearchType"] if "resolvedSearchType" in data else None,
2085
2107
  data["autoDate"] if "autoDate" in data else None,
2108
+ context=data.get("context"),
2086
2109
  cost_dollars=cost_dollars,
2087
2110
  )
2088
2111
 
@@ -2113,6 +2136,7 @@ class AsyncExa(Exa):
2113
2136
  data.get("autopromptString"),
2114
2137
  data.get("resolvedSearchType"),
2115
2138
  data.get("autoDate"),
2139
+ context=data.get("context"),
2116
2140
  cost_dollars=cost_dollars,
2117
2141
  statuses=statuses,
2118
2142
  )
@@ -2192,6 +2216,7 @@ class AsyncExa(Exa):
2192
2216
  "text",
2193
2217
  "highlights",
2194
2218
  "summary",
2219
+ "context",
2195
2220
  "subpages",
2196
2221
  "subpage_target",
2197
2222
  "livecrawl",
@@ -2208,6 +2233,7 @@ class AsyncExa(Exa):
2208
2233
  data.get("autopromptString"),
2209
2234
  data.get("resolvedSearchType"),
2210
2235
  data.get("autoDate"),
2236
+ context=data.get("context"),
2211
2237
  cost_dollars=cost_dollars,
2212
2238
  )
2213
2239
 
@@ -0,0 +1,42 @@
1
+ {% for decorator in decorators -%}
2
+ {{ decorator }}
3
+ {% endfor -%}
4
+ class {{ class_name }}({{ base_class }}):{% if comment is defined %} # {{ comment }}{% endif %}
5
+ {%- if description %}
6
+ """
7
+ {{ description | indent(4) }}
8
+ """
9
+ {%- endif %}
10
+ {%- if not fields and not description %}
11
+ pass
12
+ {%- endif %}
13
+ {%- if config %}
14
+ {%- filter indent(4) %}
15
+ {%- endfilter %}
16
+ {%- endif %}
17
+ {%- for field in fields -%}
18
+ {%- if field.name == "type" and field.field %}
19
+ type: Literal['{{ field.default }}']
20
+ {%- elif field.name == "object" and field.field %}
21
+ object: Literal['{{ field.default }}']
22
+ {%- elif not field.annotated and field.field %}
23
+ {{ field.name }}: {{ field.type_hint }} = {{ field.field }}
24
+ {%- else %}
25
+ {%- if field.annotated %}
26
+ {{ field.name }}: {{ field.annotated }}
27
+ {%- else %}
28
+ {{ field.name }}: {{ field.type_hint }}
29
+ {%- endif %}
30
+ {%- if not (field.required or (field.represented_default == 'None' and field.strip_default_none)) or field.data_type.is_optional
31
+ %} = {{ field.represented_default }}
32
+ {%- endif -%}
33
+ {%- endif %}
34
+ {%- if field.docstring %}
35
+ """
36
+ {{ field.docstring | indent(4) }}
37
+ """
38
+ {%- endif %}
39
+ {%- for method in methods -%}
40
+ {{ method }}
41
+ {%- endfor -%}
42
+ {%- endfor -%}
@@ -1,17 +1,9 @@
1
- [tool.poetry]
2
- name = "exa-py"
3
- version = "1.14.2"
4
- description = "Python SDK for Exa API."
5
- authors = ["Exa AI <hello@exa.ai>"]
6
- readme = "README.md"
7
-
8
1
  [tool.poetry.dependencies]
9
2
  python = "^3.9"
10
3
  requests = "^2.32.3"
11
4
  typing-extensions = "^4.12.2"
12
5
  openai = "^1.48"
13
6
  pydantic = "^2.10.6"
14
- pytest-mock = "^3.14.0"
15
7
  httpx = "^0.28.1"
16
8
 
17
9
  [tool.poetry.group.dev.dependencies]
@@ -22,6 +14,7 @@ twine = "^5.1.1"
22
14
  datamodel-code-generator = "^0.28.4"
23
15
  pytest = "^8.3.5"
24
16
  pytest-cov = "^6.0.0"
17
+ pytest-mock = "^3.14.0"
25
18
 
26
19
  [build-system]
27
20
  requires = ["poetry-core"]
@@ -32,7 +25,7 @@ in-project = true
32
25
 
33
26
  [project]
34
27
  name = "exa-py"
35
- version = "1.14.4"
28
+ version = "1.14.6"
36
29
  description = "Python SDK for Exa API."
37
30
  readme = "README.md"
38
31
  requires-python = ">=3.9"
@@ -43,6 +36,5 @@ dependencies = [
43
36
  "typing-extensions>=4.12.2",
44
37
  "openai>=1.48",
45
38
  "pydantic>=2.10.6",
46
- "pytest-mock>=3.14.0",
47
39
  "httpx>=0.28.1",
48
40
  ]
@@ -1,129 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: exa-py
3
- Version: 1.14.4
4
- Summary: Python SDK for Exa API.
5
- Home-page: https://github.com/exa-labs/exa-py
6
- Author: Exa
7
- Author-email: Exa AI <hello@exa.ai>
8
- License: MIT
9
- Requires-Python: >=3.9
10
- Description-Content-Type: text/markdown
11
- Requires-Dist: requests>=2.32.3
12
- Requires-Dist: typing-extensions>=4.12.2
13
- Requires-Dist: openai>=1.48
14
- Requires-Dist: pydantic>=2.10.6
15
- Requires-Dist: pytest-mock>=3.14.0
16
- Requires-Dist: httpx>=0.28.1
17
- Dynamic: author
18
- Dynamic: home-page
19
-
20
- # Exa
21
-
22
- Exa (formerly Metaphor) API in Python
23
-
24
- Note: This API is basically the same as `metaphor-python` but reflects new
25
- features associated with Metaphor's rename to Exa. New site is https://exa.ai
26
-
27
- ## Installation
28
-
29
- ```bash
30
- pip install exa_py
31
- ```
32
-
33
- ## Usage
34
-
35
- Import the package and initialize the Exa client with your API key:
36
-
37
- ```python
38
- from exa_py import Exa
39
-
40
- exa = Exa(api_key="your-api-key")
41
- ```
42
-
43
- ## Common requests
44
-
45
- ```python
46
-
47
- # basic search
48
- results = exa.search("This is a Exa query:")
49
-
50
- # keyword search (non-neural)
51
- results = exa.search("Google-style query", type="keyword")
52
-
53
- # search with date filters
54
- results = exa.search("This is a Exa query:", start_published_date="2019-01-01", end_published_date="2019-01-31")
55
-
56
- # search with domain filters
57
- results = exa.search("This is a Exa query:", include_domains=["www.cnn.com", "www.nytimes.com"])
58
-
59
- # search and get text contents
60
- results = exa.search_and_contents("This is a Exa query:")
61
-
62
- # search and get contents with contents options
63
- results = exa.search_and_contents("This is a Exa query:",
64
- text={"include_html_tags": True, "max_characters": 1000})
65
-
66
- # find similar documents
67
- results = exa.find_similar("https://example.com")
68
-
69
- # find similar excluding source domain
70
- results = exa.find_similar("https://example.com", exclude_source_domain=True)
71
-
72
- # find similar with contents
73
- results = exa.find_similar_and_contents("https://example.com", text=True)
74
-
75
- # get text contents
76
- results = exa.get_contents(["tesla.com"])
77
-
78
- # get contents with contents options
79
- results = exa.get_contents(["urls"],
80
- text={"include_html_tags": True, "max_characters": 1000})
81
-
82
- # basic answer
83
- response = exa.answer("This is a query to answer a question")
84
-
85
- # answer with full text, using the exa-pro model (sends 2 expanded quries to exa search)
86
- response = exa.answer("This is a query to answer a question", text=True, model="exa-pro")
87
-
88
- # answer with streaming
89
- response = exa.stream_answer("This is a query to answer:")
90
-
91
- # Print each chunk as it arrives when using the stream_answer method
92
- for chunk in response:
93
- print(chunk, end='', flush=True)
94
-
95
- # research task example – answer a question with citations
96
- # Example prompt & schema inspired by the TypeScript example.
97
- QUESTION = (
98
- "Summarize the history of San Francisco highlighting one or two major events "
99
- "for each decade from 1850 to 1950"
100
- )
101
- OUTPUT_SCHEMA: Dict[str, Any] = {
102
- "type": "object",
103
- "required": ["timeline"],
104
- "properties": {
105
- "timeline": {
106
- "type": "array",
107
- "items": {
108
- "type": "object",
109
- "required": ["decade", "notableEvents"],
110
- "properties": {
111
- "decade": {
112
- "type": "string",
113
- "description": 'Decade label e.g. "1850s"',
114
- },
115
- "notableEvents": {
116
- "type": "string",
117
- "description": "A summary of notable events.",
118
- },
119
- },
120
- },
121
- },
122
- },
123
- }
124
- resp = exa.research.create_task(
125
- instructions=QUESTION,
126
- model="exa-research",
127
- output_schema=OUTPUT_SCHEMA,
128
- )
129
- ```
@@ -1,35 +0,0 @@
1
- README.md
2
- pyproject.toml
3
- setup.py
4
- exa_py/__init__.py
5
- exa_py/api.py
6
- exa_py/py.typed
7
- exa_py/utils.py
8
- exa_py.egg-info/PKG-INFO
9
- exa_py.egg-info/SOURCES.txt
10
- exa_py.egg-info/dependency_links.txt
11
- exa_py.egg-info/requires.txt
12
- exa_py.egg-info/top_level.txt
13
- exa_py/research/__init__.py
14
- exa_py/research/client.py
15
- exa_py/research/models.py
16
- exa_py/websets/__init__.py
17
- exa_py/websets/client.py
18
- exa_py/websets/types.py
19
- exa_py/websets/core/__init__.py
20
- exa_py/websets/core/base.py
21
- exa_py/websets/enrichments/__init__.py
22
- exa_py/websets/enrichments/client.py
23
- exa_py/websets/items/__init__.py
24
- exa_py/websets/items/client.py
25
- exa_py/websets/monitors/__init__.py
26
- exa_py/websets/monitors/client.py
27
- exa_py/websets/monitors/runs/__init__.py
28
- exa_py/websets/monitors/runs/client.py
29
- exa_py/websets/searches/__init__.py
30
- exa_py/websets/searches/client.py
31
- exa_py/websets/webhooks/__init__.py
32
- exa_py/websets/webhooks/client.py
33
- tests/test_monitors.py
34
- tests/test_search_api.py
35
- tests/test_websets.py
@@ -1,6 +0,0 @@
1
- requests>=2.32.3
2
- typing-extensions>=4.12.2
3
- openai>=1.48
4
- pydantic>=2.10.6
5
- pytest-mock>=3.14.0
6
- httpx>=0.28.1
@@ -1 +0,0 @@
1
- exa_py
exa_py-1.14.4/setup.cfg DELETED
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
exa_py-1.14.4/setup.py DELETED
@@ -1,26 +0,0 @@
1
- from setuptools import find_packages, setup
2
-
3
- setup(
4
- name="exa_py",
5
- version="1.14.4",
6
- description="Python SDK for Exa API.",
7
- long_description_content_type="text/markdown",
8
- long_description=open("README.md").read(),
9
- author="Exa",
10
- author_email="hello@exa.ai",
11
- package_data={"exa_py": ["py.typed"]},
12
- url="https://github.com/exa-labs/exa-py",
13
- packages=find_packages(),
14
- install_requires=["requests", "typing-extensions", "openai>=1.10.0"],
15
- classifiers=[
16
- "Development Status :: 5 - Production/Stable",
17
- "Intended Audience :: Developers",
18
- "License :: OSI Approved :: MIT License",
19
- "Typing :: Typed",
20
- "Programming Language :: Python :: 3.8",
21
- "Programming Language :: Python :: 3.9",
22
- "Programming Language :: Python :: 3.10",
23
- "Programming Language :: Python :: 3.11",
24
- "Programming Language :: Python :: 3.12",
25
- ],
26
- )