diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f3e0a4..b4e9013 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.15.0" + ".": "0.16.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index f435808..66f8c27 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-4a46f38182c87694de28ad72b2ebb873d3004533dbe8db3276637d6d80cf9a33.yml -openapi_spec_hash: b10ee8536928665190a110738964fccb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-bfa54d26b675d92a0b3db3e3c2147dc98250fb1e4cb82bb6bd6f9af544763506.yml +openapi_spec_hash: 7d834a5553262d0a2538bc066f39d549 config_hash: 70354330f92ce169beabc98696ebb9a3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd6916..e9693f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.16.0 (2026-05-06) + +Full Changelog: [v0.15.0...v0.16.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.15.0...v0.16.0) + +### Features + +* **api:** api update ([aed2184](https://github.com/context-dot-dev/context-python-sdk/commit/aed2184efdd3c73b45e3df6993147b3d92414070)) + ## 0.15.0 (2026-05-05) Full Changelog: [v0.14.0...v0.15.0](https://github.com/context-dot-dev/context-python-sdk/compare/v0.14.0...v0.15.0) diff --git a/README.md b/README.md index 29a84e8..5bfddea 100644 --- a/README.md +++ b/README.md @@ -130,19 +130,11 @@ from context.dev import ContextDev client = ContextDev() -response = client.ai.ai_query( - data_to_extract=[ - { - "datapoint_description": "datapoint_description", - "datapoint_example": "datapoint_example", - "datapoint_name": "datapoint_name", - "datapoint_type": "text", - } - ], - domain="domain", - specific_pages={}, +response = client.web.web_scrape_images( + url="https://example.com", + enrichment={}, ) -print(response.specific_pages) +print(response.enrichment) ``` ## Handling errors diff --git a/pyproject.toml b/pyproject.toml index c4c9c1c..19d2e4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "context.dev" -version = "0.15.0" +version = "0.16.0" description = "The official Python library for the context.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/context/dev/_version.py b/src/context/dev/_version.py index 889cdf9..6141169 100644 --- a/src/context/dev/_version.py +++ b/src/context/dev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "context.dev" -__version__ = "0.15.0" # x-release-please-version +__version__ = "0.16.0" # x-release-please-version diff --git a/src/context/dev/resources/web.py b/src/context/dev/resources/web.py index 478d3b7..9e1fcf3 100644 --- a/src/context/dev/resources/web.py +++ b/src/context/dev/resources/web.py @@ -398,6 +398,8 @@ def web_scrape_images( self, *, url: str, + enrichment: web_web_scrape_images_params.Enrichment | Omit = omit, + max_age_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -405,14 +407,20 @@ def web_scrape_images( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WebWebScrapeImagesResponse: - """Scrapes all images from the given URL. - - Extracts images from img, svg, - picture/source, link, and video elements including inline SVGs, base64 data - URIs, and standard URLs. + """ + Extract image assets from a web page, including standard URLs, inline SVGs, data + URIs, responsive image sources, metadata, CSS backgrounds, video posters, and + embeds. The base request costs 1 credit; enrichment costs 1 credit per returned + image. Args: - url: Full URL to scrape images from (must include http:// or https:// protocol) + url: Page URL to inspect. Must include http:// or https://. + + enrichment: Optional per-image processing, sent as deep-object query params such as + enrichment[resolution]=true. + + max_age_ms: Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 + day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days). extra_headers: Send extra headers @@ -429,7 +437,14 @@ def web_scrape_images( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"url": url}, web_web_scrape_images_params.WebWebScrapeImagesParams), + query=maybe_transform( + { + "url": url, + "enrichment": enrichment, + "max_age_ms": max_age_ms, + }, + web_web_scrape_images_params.WebWebScrapeImagesParams, + ), ), cast_to=WebWebScrapeImagesResponse, ) @@ -922,6 +937,8 @@ async def web_scrape_images( self, *, url: str, + enrichment: web_web_scrape_images_params.Enrichment | Omit = omit, + max_age_ms: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -929,14 +946,20 @@ async def web_scrape_images( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WebWebScrapeImagesResponse: - """Scrapes all images from the given URL. - - Extracts images from img, svg, - picture/source, link, and video elements including inline SVGs, base64 data - URIs, and standard URLs. + """ + Extract image assets from a web page, including standard URLs, inline SVGs, data + URIs, responsive image sources, metadata, CSS backgrounds, video posters, and + embeds. The base request costs 1 credit; enrichment costs 1 credit per returned + image. Args: - url: Full URL to scrape images from (must include http:// or https:// protocol) + url: Page URL to inspect. Must include http:// or https://. + + enrichment: Optional per-image processing, sent as deep-object query params such as + enrichment[resolution]=true. + + max_age_ms: Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 + day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days). extra_headers: Send extra headers @@ -953,7 +976,14 @@ async def web_scrape_images( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform({"url": url}, web_web_scrape_images_params.WebWebScrapeImagesParams), + query=await async_maybe_transform( + { + "url": url, + "enrichment": enrichment, + "max_age_ms": max_age_ms, + }, + web_web_scrape_images_params.WebWebScrapeImagesParams, + ), ), cast_to=WebWebScrapeImagesResponse, ) diff --git a/src/context/dev/types/web_web_scrape_images_params.py b/src/context/dev/types/web_web_scrape_images_params.py index 9e89207..c32eebf 100644 --- a/src/context/dev/types/web_web_scrape_images_params.py +++ b/src/context/dev/types/web_web_scrape_images_params.py @@ -2,11 +2,47 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict -__all__ = ["WebWebScrapeImagesParams"] +from .._utils import PropertyInfo + +__all__ = ["WebWebScrapeImagesParams", "Enrichment"] class WebWebScrapeImagesParams(TypedDict, total=False): url: Required[str] - """Full URL to scrape images from (must include http:// or https:// protocol)""" + """Page URL to inspect. Must include http:// or https://.""" + + enrichment: Enrichment + """ + Optional per-image processing, sent as deep-object query params such as + enrichment[resolution]=true. + """ + + max_age_ms: Annotated[int, PropertyInfo(alias="maxAgeMs")] + """Reuse a cached result this many milliseconds old or newer. + + Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 + days). + """ + + +class Enrichment(TypedDict, total=False): + """ + Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true. + """ + + classification: bool + """Classify each image by visual asset type.""" + + hosted_url: Annotated[bool, PropertyInfo(alias="hostedUrl")] + """ + Host materializable images on the Brand.dev CDN and return their URL and MIME + type. + """ + + max_time_per_ms: Annotated[int, PropertyInfo(alias="maxTimePerMs")] + """Per-image enrichment timeout in milliseconds. Default: 6000. Maximum: 60000.""" + + resolution: bool + """Measure image width and height when possible.""" diff --git a/src/context/dev/types/web_web_scrape_images_response.py b/src/context/dev/types/web_web_scrape_images_response.py index c1622c7..6bb1144 100644 --- a/src/context/dev/types/web_web_scrape_images_response.py +++ b/src/context/dev/types/web_web_scrape_images_response.py @@ -5,29 +5,53 @@ from .._models import BaseModel -__all__ = ["WebWebScrapeImagesResponse", "Image"] +__all__ = ["WebWebScrapeImagesResponse", "Image", "ImageEnrichment"] + + +class ImageEnrichment(BaseModel): + """Requested metadata for images that could be processed.""" + + height: Optional[int] = None + """Image height in pixels, when measured.""" + + mimetype: Optional[str] = None + """Detected MIME type, when hosted.""" + + type: Optional[ + Literal["photography", "illustration", "logo", "wordmark", "icon", "pattern", "graphic", "other"] + ] = None + """Visual asset category, when classified.""" + + url: Optional[str] = None + """Brand.dev CDN URL, when hosted.""" + + width: Optional[int] = None + """Image width in pixels, when measured.""" class Image(BaseModel): alt: Optional[str] = None - """Alt text of the image, or null if not present""" + """Image alt text, or null when unavailable.""" element: Literal["img", "svg", "link", "source", "video", "css", "object", "meta", "background"] - """The HTML element the image was found in""" + """Where the image was found.""" src: str - """The image source - can be a URL, inline HTML (for SVGs), or a base64 data URI""" + """Original image value: URL, inline SVG or HTML, or base64 data URI.""" type: Literal["url", "html", "base64"] - """The type/format of the src value""" + """Format of src.""" + + enrichment: Optional[ImageEnrichment] = None + """Requested metadata for images that could be processed.""" class WebWebScrapeImagesResponse(BaseModel): images: List[Image] - """Array of scraped images""" + """Images found on the page.""" success: Literal[True] - """Indicates success""" + """Always true on success.""" url: str - """The URL that was scraped""" + """Page URL that was scraped.""" diff --git a/tests/api_resources/test_web.py b/tests/api_resources/test_web.py index 25f999f..dfb1711 100644 --- a/tests/api_resources/test_web.py +++ b/tests/api_resources/test_web.py @@ -248,6 +248,21 @@ def test_method_web_scrape_images(self, client: ContextDev) -> None: ) assert_matches_type(WebWebScrapeImagesResponse, web, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_images_with_all_params(self, client: ContextDev) -> None: + web = client.web.web_scrape_images( + url="https://example.com", + enrichment={ + "classification": True, + "hosted_url": True, + "max_time_per_ms": 1, + "resolution": True, + }, + max_age_ms=0, + ) + assert_matches_type(WebWebScrapeImagesResponse, web, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_web_scrape_images(self, client: ContextDev) -> None: @@ -595,6 +610,21 @@ async def test_method_web_scrape_images(self, async_client: AsyncContextDev) -> ) assert_matches_type(WebWebScrapeImagesResponse, web, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_images_with_all_params(self, async_client: AsyncContextDev) -> None: + web = await async_client.web.web_scrape_images( + url="https://example.com", + enrichment={ + "classification": True, + "hosted_url": True, + "max_time_per_ms": 1, + "resolution": True, + }, + max_age_ms=0, + ) + assert_matches_type(WebWebScrapeImagesResponse, web, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_web_scrape_images(self, async_client: AsyncContextDev) -> None: