Skip to content

Commit 0d3b871

Browse files
authored
Merge pull request #10 from context-dot-dev/release-please--branches--main--changes--next
release: 0.8.0
2 parents 65a7805 + 0b47fd4 commit 0d3b871

33 files changed

Lines changed: 836 additions & 807 deletions

‎.release-please-manifest.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.7.0"
2+
".": "0.8.0"
33
}

‎.stats.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 21
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev%2Fcontext.dev-5ee7a321f8e01d2678d56277f011f71294c2b8ac4d0cff0bda412362c0d9cf73.yml
3-
openapi_spec_hash: bf5d57e3bddb6975770cf85c267b5035
4-
config_hash: 682b89b02a20f5d1c13e2c91ecbcf5ce
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev%2Fcontext.dev-5afee68d7308a77a9ef51fb53917080746f96327c6d745fc029363a7d1494c3c.yml
3+
openapi_spec_hash: b2e32bb58d92a00f6ede04c4f7bf1a34
4+
config_hash: 7d13dca2b2c6f71fc463cb6062efa5ea

‎CHANGELOG.md‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
## 0.8.0 (2026-04-19)
4+
5+
Full Changelog: [v0.7.0...v0.8.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.7.0...v0.8.0)
6+
7+
### Features
8+
9+
* **api:** api update ([512bf26](https://github.com/context-dot-dev/context-python-sdk/commit/512bf2610e59733e0e950531ca9e6018a5446672))
10+
* **api:** api update ([f98376c](https://github.com/context-dot-dev/context-python-sdk/commit/f98376cf22a331138f716f8abeb4458a8e1e38c2))
11+
* **api:** api update ([9ddc161](https://github.com/context-dot-dev/context-python-sdk/commit/9ddc161215cd12384152295997b95d5ac44bec08))
12+
* **api:** api update ([639075e](https://github.com/context-dot-dev/context-python-sdk/commit/639075e0a0aa6203375592b8b67438ae0719ca26))
13+
* **api:** api update ([707a6c3](https://github.com/context-dot-dev/context-python-sdk/commit/707a6c3e49096e2248ec9e4ae7e683138647c2d6))
14+
* **api:** api update ([bbc2458](https://github.com/context-dot-dev/context-python-sdk/commit/bbc2458c38933208b22e234d6bf1f1ffee7f883e))
15+
* **api:** api update ([241bacf](https://github.com/context-dot-dev/context-python-sdk/commit/241bacf196c1e316aef39429e3919fda1c5a78eb))
16+
* **api:** api update ([648e71b](https://github.com/context-dot-dev/context-python-sdk/commit/648e71bf7afb870dceafe6485bf47932c74ebe1b))
17+
* **api:** api update ([656e585](https://github.com/context-dot-dev/context-python-sdk/commit/656e585bcdf228d8651cdab5ee37f1119a51eafa))
18+
* **api:** api update ([3fc9944](https://github.com/context-dot-dev/context-python-sdk/commit/3fc9944ff014539c18e0216b93c936c1df2b0219))
19+
* **api:** api update ([b9374f5](https://github.com/context-dot-dev/context-python-sdk/commit/b9374f57a2a0ed207c39e80b6fbf710bbe170e11))
20+
* **api:** manual updates ([2af78a4](https://github.com/context-dot-dev/context-python-sdk/commit/2af78a43c1e9b5654668e82c009b679dc3ae8e73))
21+
* **api:** manual updates ([d6acbc6](https://github.com/context-dot-dev/context-python-sdk/commit/d6acbc6552d84e58a6ff7a9e99952a2a7a624647))
22+
* **api:** manual updates ([ec8ff2d](https://github.com/context-dot-dev/context-python-sdk/commit/ec8ff2d2a0d84fcb0c05791fa913441c60ed9c24))
23+
24+
25+
### Bug Fixes
26+
27+
* ensure file data are only sent as 1 parameter ([7c314a2](https://github.com/context-dot-dev/context-python-sdk/commit/7c314a29f73103eb592686df101c86c6cfd26b3f))
28+
29+
30+
### Performance Improvements
31+
32+
* **client:** optimize file structure copying in multipart requests ([573a70c](https://github.com/context-dot-dev/context-python-sdk/commit/573a70cee8cb9bed8377f816bfba419ecbe86109))
33+
334
## 0.7.0 (2026-04-09)
435

536
Full Changelog: [v0.6.0...v0.7.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.6.0...v0.7.0)

‎api.md‎

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Types:
44

55
```python
66
from context.dev.types import (
7+
WebExtractFontsResponse,
8+
WebExtractStyleguideResponse,
79
WebScreenshotResponse,
810
WebWebCrawlMdResponse,
911
WebWebScrapeHTMLResponse,
@@ -15,7 +17,9 @@ from context.dev.types import (
1517

1618
Methods:
1719

18-
- <code title="get /brand/screenshot">client.web.<a href="./src/context/dev/resources/web.py">screenshot</a>(\*\*<a href="src/context/dev/types/web_screenshot_params.py">params</a>) -> <a href="./src/context/dev/types/web_screenshot_response.py">WebScreenshotResponse</a></code>
20+
- <code title="get /web/fonts">client.web.<a href="./src/context/dev/resources/web.py">extract_fonts</a>(\*\*<a href="src/context/dev/types/web_extract_fonts_params.py">params</a>) -> <a href="./src/context/dev/types/web_extract_fonts_response.py">WebExtractFontsResponse</a></code>
21+
- <code title="get /web/styleguide">client.web.<a href="./src/context/dev/resources/web.py">extract_styleguide</a>(\*\*<a href="src/context/dev/types/web_extract_styleguide_params.py">params</a>) -> <a href="./src/context/dev/types/web_extract_styleguide_response.py">WebExtractStyleguideResponse</a></code>
22+
- <code title="get /web/screenshot">client.web.<a href="./src/context/dev/resources/web.py">screenshot</a>(\*\*<a href="src/context/dev/types/web_screenshot_params.py">params</a>) -> <a href="./src/context/dev/types/web_screenshot_response.py">WebScreenshotResponse</a></code>
1923
- <code title="post /web/crawl">client.web.<a href="./src/context/dev/resources/web.py">web_crawl_md</a>(\*\*<a href="src/context/dev/types/web_web_crawl_md_params.py">params</a>) -> <a href="./src/context/dev/types/web_web_crawl_md_response.py">WebWebCrawlMdResponse</a></code>
2024
- <code title="get /web/scrape/html">client.web.<a href="./src/context/dev/resources/web.py">web_scrape_html</a>(\*\*<a href="src/context/dev/types/web_web_scrape_html_params.py">params</a>) -> <a href="./src/context/dev/types/web_web_scrape_html_response.py">WebWebScrapeHTMLResponse</a></code>
2125
- <code title="get /web/scrape/images">client.web.<a href="./src/context/dev/resources/web.py">web_scrape_images</a>(\*\*<a href="src/context/dev/types/web_web_scrape_images_params.py">params</a>) -> <a href="./src/context/dev/types/web_web_scrape_images_response.py">WebWebScrapeImagesResponse</a></code>
@@ -36,19 +40,6 @@ Methods:
3640
- <code title="post /brand/ai/product">client.ai.<a href="./src/context/dev/resources/ai.py">extract_product</a>(\*\*<a href="src/context/dev/types/ai_extract_product_params.py">params</a>) -> <a href="./src/context/dev/types/ai_extract_product_response.py">AIExtractProductResponse</a></code>
3741
- <code title="post /brand/ai/products">client.ai.<a href="./src/context/dev/resources/ai.py">extract_products</a>(\*\*<a href="src/context/dev/types/ai_extract_products_params.py">params</a>) -> <a href="./src/context/dev/types/ai_extract_products_response.py">AIExtractProductsResponse</a></code>
3842

39-
# Style
40-
41-
Types:
42-
43-
```python
44-
from context.dev.types import StyleExtractFontsResponse, StyleExtractStyleguideResponse
45-
```
46-
47-
Methods:
48-
49-
- <code title="get /brand/fonts">client.style.<a href="./src/context/dev/resources/style.py">extract_fonts</a>(\*\*<a href="src/context/dev/types/style_extract_fonts_params.py">params</a>) -> <a href="./src/context/dev/types/style_extract_fonts_response.py">StyleExtractFontsResponse</a></code>
50-
- <code title="get /brand/styleguide">client.style.<a href="./src/context/dev/resources/style.py">extract_styleguide</a>(\*\*<a href="src/context/dev/types/style_extract_styleguide_params.py">params</a>) -> <a href="./src/context/dev/types/style_extract_styleguide_response.py">StyleExtractStyleguideResponse</a></code>
51-
5243
# Brand
5344

5445
Types:
@@ -85,7 +76,7 @@ from context.dev.types import IndustryRetrieveNaicsResponse
8576

8677
Methods:
8778

88-
- <code title="get /brand/naics">client.industry.<a href="./src/context/dev/resources/industry.py">retrieve_naics</a>(\*\*<a href="src/context/dev/types/industry_retrieve_naics_params.py">params</a>) -> <a href="./src/context/dev/types/industry_retrieve_naics_response.py">IndustryRetrieveNaicsResponse</a></code>
79+
- <code title="get /web/naics">client.industry.<a href="./src/context/dev/resources/industry.py">retrieve_naics</a>(\*\*<a href="src/context/dev/types/industry_retrieve_naics_params.py">params</a>) -> <a href="./src/context/dev/types/industry_retrieve_naics_response.py">IndustryRetrieveNaicsResponse</a></code>
8980

9081
# Utility
9182

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "context.dev"
3-
version = "0.7.0"
3+
version = "0.8.0"
44
description = "The official Python library for the context.dev API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"

‎src/context/dev/_client.py‎

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@
3131
)
3232

3333
if TYPE_CHECKING:
34-
from .resources import ai, web, brand, style, utility, industry
34+
from .resources import ai, web, brand, utility, industry
3535
from .resources.ai import AIResource, AsyncAIResource
3636
from .resources.web import WebResource, AsyncWebResource
3737
from .resources.brand import BrandResource, AsyncBrandResource
38-
from .resources.style import StyleResource, AsyncStyleResource
3938
from .resources.utility import UtilityResource, AsyncUtilityResource
4039
from .resources.industry import IndustryResource, AsyncIndustryResource
4140

@@ -118,12 +117,6 @@ def ai(self) -> AIResource:
118117

119118
return AIResource(self)
120119

121-
@cached_property
122-
def style(self) -> StyleResource:
123-
from .resources.style import StyleResource
124-
125-
return StyleResource(self)
126-
127120
@cached_property
128121
def brand(self) -> BrandResource:
129122
from .resources.brand import BrandResource
@@ -322,12 +315,6 @@ def ai(self) -> AsyncAIResource:
322315

323316
return AsyncAIResource(self)
324317

325-
@cached_property
326-
def style(self) -> AsyncStyleResource:
327-
from .resources.style import AsyncStyleResource
328-
329-
return AsyncStyleResource(self)
330-
331318
@cached_property
332319
def brand(self) -> AsyncBrandResource:
333320
from .resources.brand import AsyncBrandResource
@@ -477,12 +464,6 @@ def ai(self) -> ai.AIResourceWithRawResponse:
477464

478465
return AIResourceWithRawResponse(self._client.ai)
479466

480-
@cached_property
481-
def style(self) -> style.StyleResourceWithRawResponse:
482-
from .resources.style import StyleResourceWithRawResponse
483-
484-
return StyleResourceWithRawResponse(self._client.style)
485-
486467
@cached_property
487468
def brand(self) -> brand.BrandResourceWithRawResponse:
488469
from .resources.brand import BrandResourceWithRawResponse
@@ -520,12 +501,6 @@ def ai(self) -> ai.AsyncAIResourceWithRawResponse:
520501

521502
return AsyncAIResourceWithRawResponse(self._client.ai)
522503

523-
@cached_property
524-
def style(self) -> style.AsyncStyleResourceWithRawResponse:
525-
from .resources.style import AsyncStyleResourceWithRawResponse
526-
527-
return AsyncStyleResourceWithRawResponse(self._client.style)
528-
529504
@cached_property
530505
def brand(self) -> brand.AsyncBrandResourceWithRawResponse:
531506
from .resources.brand import AsyncBrandResourceWithRawResponse
@@ -563,12 +538,6 @@ def ai(self) -> ai.AIResourceWithStreamingResponse:
563538

564539
return AIResourceWithStreamingResponse(self._client.ai)
565540

566-
@cached_property
567-
def style(self) -> style.StyleResourceWithStreamingResponse:
568-
from .resources.style import StyleResourceWithStreamingResponse
569-
570-
return StyleResourceWithStreamingResponse(self._client.style)
571-
572541
@cached_property
573542
def brand(self) -> brand.BrandResourceWithStreamingResponse:
574543
from .resources.brand import BrandResourceWithStreamingResponse
@@ -606,12 +575,6 @@ def ai(self) -> ai.AsyncAIResourceWithStreamingResponse:
606575

607576
return AsyncAIResourceWithStreamingResponse(self._client.ai)
608577

609-
@cached_property
610-
def style(self) -> style.AsyncStyleResourceWithStreamingResponse:
611-
from .resources.style import AsyncStyleResourceWithStreamingResponse
612-
613-
return AsyncStyleResourceWithStreamingResponse(self._client.style)
614-
615578
@cached_property
616579
def brand(self) -> brand.AsyncBrandResourceWithStreamingResponse:
617580
from .resources.brand import AsyncBrandResourceWithStreamingResponse

‎src/context/dev/_files.py‎

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import io
44
import os
55
import pathlib
6-
from typing import overload
7-
from typing_extensions import TypeGuard
6+
from typing import Sequence, cast, overload
7+
from typing_extensions import TypeVar, TypeGuard
88

99
import anyio
1010

@@ -17,7 +17,9 @@
1717
HttpxFileContent,
1818
HttpxRequestFiles,
1919
)
20-
from ._utils import is_tuple_t, is_mapping_t, is_sequence_t
20+
from ._utils import is_list, is_mapping, is_tuple_t, is_mapping_t, is_sequence_t
21+
22+
_T = TypeVar("_T")
2123

2224

2325
def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]:
@@ -121,3 +123,51 @@ async def async_read_file_content(file: FileContent) -> HttpxFileContent:
121123
return await anyio.Path(file).read_bytes()
122124

123125
return file
126+
127+
128+
def deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]]) -> _T:
129+
"""Copy only the containers along the given paths.
130+
131+
Used to guard against mutation by extract_files without copying the entire structure.
132+
Only dicts and lists that lie on a path are copied; everything else
133+
is returned by reference.
134+
135+
For example, given paths=[["foo", "files", "file"]] and the structure:
136+
{
137+
"foo": {
138+
"bar": {"baz": {}},
139+
"files": {"file": <content>}
140+
}
141+
}
142+
The root dict, "foo", and "files" are copied (they lie on the path).
143+
"bar" and "baz" are returned by reference (off the path).
144+
"""
145+
return _deepcopy_with_paths(item, paths, 0)
146+
147+
148+
def _deepcopy_with_paths(item: _T, paths: Sequence[Sequence[str]], index: int) -> _T:
149+
if not paths:
150+
return item
151+
if is_mapping(item):
152+
key_to_paths: dict[str, list[Sequence[str]]] = {}
153+
for path in paths:
154+
if index < len(path):
155+
key_to_paths.setdefault(path[index], []).append(path)
156+
157+
# if no path continues through this mapping, it won't be mutated and copying it is redundant
158+
if not key_to_paths:
159+
return item
160+
161+
result = dict(item)
162+
for key, subpaths in key_to_paths.items():
163+
if key in result:
164+
result[key] = _deepcopy_with_paths(result[key], subpaths, index + 1)
165+
return cast(_T, result)
166+
if is_list(item):
167+
array_paths = [path for path in paths if index < len(path) and path[index] == "<array>"]
168+
169+
# if no path expects a list here, nothing will be mutated inside it - return by reference
170+
if not array_paths:
171+
return cast(_T, item)
172+
return cast(_T, [_deepcopy_with_paths(entry, array_paths, index + 1) for entry in item])
173+
return item

‎src/context/dev/_utils/__init__.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
coerce_integer as coerce_integer,
2525
file_from_path as file_from_path,
2626
strip_not_given as strip_not_given,
27-
deepcopy_minimal as deepcopy_minimal,
2827
get_async_library as get_async_library,
2928
maybe_coerce_float as maybe_coerce_float,
3029
get_required_header as get_required_header,

‎src/context/dev/_utils/_utils.py‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ def _extract_items(
8686
index += 1
8787
if is_dict(obj):
8888
try:
89-
# We are at the last entry in the path so we must remove the field
90-
if (len(path)) == index:
89+
# Remove the field if there are no more dict keys in the path,
90+
# only "<array>" traversal markers or end.
91+
if all(p == "<array>" for p in path[index:]):
9192
item = obj.pop(key)
9293
else:
9394
item = obj[key]
@@ -176,21 +177,6 @@ def is_iterable(obj: object) -> TypeGuard[Iterable[object]]:
176177
return isinstance(obj, Iterable)
177178

178179

179-
def deepcopy_minimal(item: _T) -> _T:
180-
"""Minimal reimplementation of copy.deepcopy() that will only copy certain object types:
181-
182-
- mappings, e.g. `dict`
183-
- list
184-
185-
This is done for performance reasons.
186-
"""
187-
if is_mapping(item):
188-
return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()})
189-
if is_list(item):
190-
return cast(_T, [deepcopy_minimal(entry) for entry in item])
191-
return item
192-
193-
194180
# copied from https://github.com/Rapptz/RoboDanny
195181
def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str:
196182
size = len(seq)

‎src/context/dev/_version.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "context.dev"
4-
__version__ = "0.7.0" # x-release-please-version
4+
__version__ = "0.8.0" # x-release-please-version

0 commit comments

Comments
 (0)