diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5334cb4..257e308 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.33.0" + ".": "1.34.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d2dca25..aaa0f9f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-98ef96cef5b06ad7a29dadba48258da7d9ea0a2b3938dc9e714ae06eb9afa1a3.yml -openapi_spec_hash: 9e957a30999dff7d4ada925e437bd202 -config_hash: c3aaaa9794dba44d524c06591ab17894 +configured_endpoints: 20 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2cdd67823c6ac9d1ab68032a695c31a098ad285ffb0c073b9dfc00afe5de9b88.yml +openapi_spec_hash: ac8a965beb9b667b6204a5c573507219 +config_hash: 4cd3173ea1cce7183640aae49cfbb374 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4848f98..9ea6d90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.34.0 (2026-02-23) + +Full Changelog: [v1.33.0...v1.34.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.33.0...v1.34.0) + +### Features + +* **api:** manual updates ([5a4711d](https://github.com/brand-dot-dev/python-sdk/commit/5a4711dd78aa1a27c8ed0318aab099a60a6a6363)) + ## 1.33.0 (2026-02-22) Full Changelog: [v1.32.0...v1.33.0](https://github.com/brand-dot-dev/python-sdk/compare/v1.32.0...v1.33.0) diff --git a/api.md b/api.md index a5e159f..8b5d705 100644 --- a/api.md +++ b/api.md @@ -20,6 +20,10 @@ from brand.dev.types import ( BrandRetrieveSimplifiedResponse, BrandScreenshotResponse, BrandStyleguideResponse, + BrandWebScrapeHTMLResponse, + BrandWebScrapeImagesResponse, + BrandWebScrapeMdResponse, + BrandWebScrapeSitemapResponse, ) ``` @@ -41,3 +45,7 @@ Methods: - client.brand.retrieve_simplified(\*\*params) -> BrandRetrieveSimplifiedResponse - client.brand.screenshot(\*\*params) -> BrandScreenshotResponse - client.brand.styleguide(\*\*params) -> BrandStyleguideResponse +- client.brand.web_scrape_html(\*\*params) -> BrandWebScrapeHTMLResponse +- client.brand.web_scrape_images(\*\*params) -> BrandWebScrapeImagesResponse +- client.brand.web_scrape_md(\*\*params) -> BrandWebScrapeMdResponse +- client.brand.web_scrape_sitemap(\*\*params) -> BrandWebScrapeSitemapResponse diff --git a/pyproject.toml b/pyproject.toml index 7927fb9..373c9b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "brand.dev" -version = "1.33.0" +version = "1.34.0" description = "The official Python library for the brand.dev API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/brand/dev/_version.py b/src/brand/dev/_version.py index 717f27d..c0aece0 100644 --- a/src/brand/dev/_version.py +++ b/src/brand/dev/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "brand.dev" -__version__ = "1.33.0" # x-release-please-version +__version__ = "1.34.0" # x-release-please-version diff --git a/src/brand/dev/resources/brand.py b/src/brand/dev/resources/brand.py index 0e290f7..f81e0d6 100644 --- a/src/brand/dev/resources/brand.py +++ b/src/brand/dev/resources/brand.py @@ -16,12 +16,16 @@ brand_screenshot_params, brand_styleguide_params, brand_ai_products_params, + brand_web_scrape_md_params, brand_retrieve_naics_params, + brand_web_scrape_html_params, brand_retrieve_by_isin_params, brand_retrieve_by_name_params, brand_prefetch_by_email_params, brand_retrieve_by_email_params, + brand_web_scrape_images_params, brand_retrieve_by_ticker_params, + brand_web_scrape_sitemap_params, brand_retrieve_simplified_params, brand_identify_from_transaction_params, ) @@ -44,12 +48,16 @@ from ..types.brand_screenshot_response import BrandScreenshotResponse from ..types.brand_styleguide_response import BrandStyleguideResponse from ..types.brand_ai_products_response import BrandAIProductsResponse +from ..types.brand_web_scrape_md_response import BrandWebScrapeMdResponse from ..types.brand_retrieve_naics_response import BrandRetrieveNaicsResponse +from ..types.brand_web_scrape_html_response import BrandWebScrapeHTMLResponse from ..types.brand_retrieve_by_isin_response import BrandRetrieveByIsinResponse from ..types.brand_retrieve_by_name_response import BrandRetrieveByNameResponse from ..types.brand_prefetch_by_email_response import BrandPrefetchByEmailResponse from ..types.brand_retrieve_by_email_response import BrandRetrieveByEmailResponse +from ..types.brand_web_scrape_images_response import BrandWebScrapeImagesResponse from ..types.brand_retrieve_by_ticker_response import BrandRetrieveByTickerResponse +from ..types.brand_web_scrape_sitemap_response import BrandWebScrapeSitemapResponse from ..types.brand_retrieve_simplified_response import BrandRetrieveSimplifiedResponse from ..types.brand_identify_from_transaction_response import BrandIdentifyFromTransactionResponse @@ -1697,6 +1705,178 @@ def styleguide( cast_to=BrandStyleguideResponse, ) + def web_scrape_html( + self, + *, + url: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeHTMLResponse: + """Scrapes the given URL and returns the raw HTML content of the page. + + Uses + automatic proxy escalation to handle blocked sites. + + Args: + url: Full URL to scrape (must include http:// or https:// protocol) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/web/scrape/html", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"url": url}, brand_web_scrape_html_params.BrandWebScrapeHTMLParams), + ), + cast_to=BrandWebScrapeHTMLResponse, + ) + + def web_scrape_images( + self, + *, + url: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeImagesResponse: + """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. + + Args: + url: Full URL to scrape images from (must include http:// or https:// protocol) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/web/scrape/images", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"url": url}, brand_web_scrape_images_params.BrandWebScrapeImagesParams), + ), + cast_to=BrandWebScrapeImagesResponse, + ) + + def web_scrape_md( + self, + *, + url: str, + include_images: bool | Omit = omit, + include_links: bool | 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeMdResponse: + """ + Scrapes the given URL, converts the HTML content to GitHub Flavored Markdown + (GFM), and returns the result. Uses automatic proxy escalation to handle blocked + sites. + + Args: + url: Full URL to scrape and convert to markdown (must include http:// or https:// + protocol) + + include_images: Include image references in Markdown output + + include_links: Preserve hyperlinks in Markdown output + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/web/scrape/markdown", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "url": url, + "include_images": include_images, + "include_links": include_links, + }, + brand_web_scrape_md_params.BrandWebScrapeMdParams, + ), + ), + cast_to=BrandWebScrapeMdResponse, + ) + + def web_scrape_sitemap( + self, + *, + domain: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeSitemapResponse: + """ + Crawls the sitemap of the given domain and returns all discovered page URLs. + Supports sitemap index files (recursive), parallel fetching with concurrency + control, deduplication, and filters out non-page resources (images, PDFs, etc.). + + Args: + domain: Domain name to crawl sitemaps for (e.g., 'example.com'). The domain will be + automatically normalized and validated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/web/scrape/sitemap", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"domain": domain}, brand_web_scrape_sitemap_params.BrandWebScrapeSitemapParams), + ), + cast_to=BrandWebScrapeSitemapResponse, + ) + class AsyncBrandResource(AsyncAPIResource): @cached_property @@ -3339,6 +3519,182 @@ async def styleguide( cast_to=BrandStyleguideResponse, ) + async def web_scrape_html( + self, + *, + url: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeHTMLResponse: + """Scrapes the given URL and returns the raw HTML content of the page. + + Uses + automatic proxy escalation to handle blocked sites. + + Args: + url: Full URL to scrape (must include http:// or https:// protocol) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/web/scrape/html", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"url": url}, brand_web_scrape_html_params.BrandWebScrapeHTMLParams), + ), + cast_to=BrandWebScrapeHTMLResponse, + ) + + async def web_scrape_images( + self, + *, + url: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeImagesResponse: + """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. + + Args: + url: Full URL to scrape images from (must include http:// or https:// protocol) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/web/scrape/images", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"url": url}, brand_web_scrape_images_params.BrandWebScrapeImagesParams + ), + ), + cast_to=BrandWebScrapeImagesResponse, + ) + + async def web_scrape_md( + self, + *, + url: str, + include_images: bool | Omit = omit, + include_links: bool | 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeMdResponse: + """ + Scrapes the given URL, converts the HTML content to GitHub Flavored Markdown + (GFM), and returns the result. Uses automatic proxy escalation to handle blocked + sites. + + Args: + url: Full URL to scrape and convert to markdown (must include http:// or https:// + protocol) + + include_images: Include image references in Markdown output + + include_links: Preserve hyperlinks in Markdown output + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/web/scrape/markdown", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "url": url, + "include_images": include_images, + "include_links": include_links, + }, + brand_web_scrape_md_params.BrandWebScrapeMdParams, + ), + ), + cast_to=BrandWebScrapeMdResponse, + ) + + async def web_scrape_sitemap( + self, + *, + domain: str, + # 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BrandWebScrapeSitemapResponse: + """ + Crawls the sitemap of the given domain and returns all discovered page URLs. + Supports sitemap index files (recursive), parallel fetching with concurrency + control, deduplication, and filters out non-page resources (images, PDFs, etc.). + + Args: + domain: Domain name to crawl sitemaps for (e.g., 'example.com'). The domain will be + automatically normalized and validated. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/web/scrape/sitemap", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"domain": domain}, brand_web_scrape_sitemap_params.BrandWebScrapeSitemapParams + ), + ), + cast_to=BrandWebScrapeSitemapResponse, + ) + class BrandResourceWithRawResponse: def __init__(self, brand: BrandResource) -> None: @@ -3392,6 +3748,18 @@ def __init__(self, brand: BrandResource) -> None: self.styleguide = to_raw_response_wrapper( brand.styleguide, ) + self.web_scrape_html = to_raw_response_wrapper( + brand.web_scrape_html, + ) + self.web_scrape_images = to_raw_response_wrapper( + brand.web_scrape_images, + ) + self.web_scrape_md = to_raw_response_wrapper( + brand.web_scrape_md, + ) + self.web_scrape_sitemap = to_raw_response_wrapper( + brand.web_scrape_sitemap, + ) class AsyncBrandResourceWithRawResponse: @@ -3446,6 +3814,18 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.styleguide = async_to_raw_response_wrapper( brand.styleguide, ) + self.web_scrape_html = async_to_raw_response_wrapper( + brand.web_scrape_html, + ) + self.web_scrape_images = async_to_raw_response_wrapper( + brand.web_scrape_images, + ) + self.web_scrape_md = async_to_raw_response_wrapper( + brand.web_scrape_md, + ) + self.web_scrape_sitemap = async_to_raw_response_wrapper( + brand.web_scrape_sitemap, + ) class BrandResourceWithStreamingResponse: @@ -3500,6 +3880,18 @@ def __init__(self, brand: BrandResource) -> None: self.styleguide = to_streamed_response_wrapper( brand.styleguide, ) + self.web_scrape_html = to_streamed_response_wrapper( + brand.web_scrape_html, + ) + self.web_scrape_images = to_streamed_response_wrapper( + brand.web_scrape_images, + ) + self.web_scrape_md = to_streamed_response_wrapper( + brand.web_scrape_md, + ) + self.web_scrape_sitemap = to_streamed_response_wrapper( + brand.web_scrape_sitemap, + ) class AsyncBrandResourceWithStreamingResponse: @@ -3554,3 +3946,15 @@ def __init__(self, brand: AsyncBrandResource) -> None: self.styleguide = async_to_streamed_response_wrapper( brand.styleguide, ) + self.web_scrape_html = async_to_streamed_response_wrapper( + brand.web_scrape_html, + ) + self.web_scrape_images = async_to_streamed_response_wrapper( + brand.web_scrape_images, + ) + self.web_scrape_md = async_to_streamed_response_wrapper( + brand.web_scrape_md, + ) + self.web_scrape_sitemap = async_to_streamed_response_wrapper( + brand.web_scrape_sitemap, + ) diff --git a/src/brand/dev/types/__init__.py b/src/brand/dev/types/__init__.py index 88b9a02..2b7129d 100644 --- a/src/brand/dev/types/__init__.py +++ b/src/brand/dev/types/__init__.py @@ -18,19 +18,27 @@ from .brand_screenshot_response import BrandScreenshotResponse as BrandScreenshotResponse from .brand_styleguide_response import BrandStyleguideResponse as BrandStyleguideResponse from .brand_ai_products_response import BrandAIProductsResponse as BrandAIProductsResponse +from .brand_web_scrape_md_params import BrandWebScrapeMdParams as BrandWebScrapeMdParams from .brand_retrieve_naics_params import BrandRetrieveNaicsParams as BrandRetrieveNaicsParams +from .brand_web_scrape_html_params import BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams +from .brand_web_scrape_md_response import BrandWebScrapeMdResponse as BrandWebScrapeMdResponse from .brand_retrieve_by_isin_params import BrandRetrieveByIsinParams as BrandRetrieveByIsinParams from .brand_retrieve_by_name_params import BrandRetrieveByNameParams as BrandRetrieveByNameParams from .brand_retrieve_naics_response import BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse from .brand_prefetch_by_email_params import BrandPrefetchByEmailParams as BrandPrefetchByEmailParams from .brand_retrieve_by_email_params import BrandRetrieveByEmailParams as BrandRetrieveByEmailParams +from .brand_web_scrape_html_response import BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse +from .brand_web_scrape_images_params import BrandWebScrapeImagesParams as BrandWebScrapeImagesParams from .brand_retrieve_by_isin_response import BrandRetrieveByIsinResponse as BrandRetrieveByIsinResponse from .brand_retrieve_by_name_response import BrandRetrieveByNameResponse as BrandRetrieveByNameResponse from .brand_retrieve_by_ticker_params import BrandRetrieveByTickerParams as BrandRetrieveByTickerParams +from .brand_web_scrape_sitemap_params import BrandWebScrapeSitemapParams as BrandWebScrapeSitemapParams from .brand_prefetch_by_email_response import BrandPrefetchByEmailResponse as BrandPrefetchByEmailResponse from .brand_retrieve_by_email_response import BrandRetrieveByEmailResponse as BrandRetrieveByEmailResponse from .brand_retrieve_simplified_params import BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams +from .brand_web_scrape_images_response import BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse from .brand_retrieve_by_ticker_response import BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse +from .brand_web_scrape_sitemap_response import BrandWebScrapeSitemapResponse as BrandWebScrapeSitemapResponse from .brand_retrieve_simplified_response import BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse from .brand_identify_from_transaction_params import ( BrandIdentifyFromTransactionParams as BrandIdentifyFromTransactionParams, diff --git a/src/brand/dev/types/brand_web_scrape_html_params.py b/src/brand/dev/types/brand_web_scrape_html_params.py new file mode 100644 index 0000000..86246f4 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_html_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrandWebScrapeHTMLParams"] + + +class BrandWebScrapeHTMLParams(TypedDict, total=False): + url: Required[str] + """Full URL to scrape (must include http:// or https:// protocol)""" diff --git a/src/brand/dev/types/brand_web_scrape_html_response.py b/src/brand/dev/types/brand_web_scrape_html_response.py new file mode 100644 index 0000000..a33cb79 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_html_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["BrandWebScrapeHTMLResponse"] + + +class BrandWebScrapeHTMLResponse(BaseModel): + html: str + """Raw HTML content of the page""" + + success: Literal[True] + """Indicates success""" + + url: str + """The URL that was scraped""" diff --git a/src/brand/dev/types/brand_web_scrape_images_params.py b/src/brand/dev/types/brand_web_scrape_images_params.py new file mode 100644 index 0000000..665c5f0 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_images_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrandWebScrapeImagesParams"] + + +class BrandWebScrapeImagesParams(TypedDict, total=False): + url: Required[str] + """Full URL to scrape images from (must include http:// or https:// protocol)""" diff --git a/src/brand/dev/types/brand_web_scrape_images_response.py b/src/brand/dev/types/brand_web_scrape_images_response.py new file mode 100644 index 0000000..e97d79a --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_images_response.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["BrandWebScrapeImagesResponse", "Image"] + + +class Image(BaseModel): + alt: Optional[str] = None + """Alt text of the image, or null if not present""" + + element: Literal["img", "svg", "link", "source", "video"] + """The HTML element the image was found in""" + + src: str + """The image source - can be a URL, inline HTML (for SVGs), or a base64 data URI""" + + type: Literal["url", "html", "base64"] + """The type/format of the src value""" + + +class BrandWebScrapeImagesResponse(BaseModel): + images: List[Image] + """Array of scraped images""" + + success: Literal[True] + """Indicates success""" + + url: str + """The URL that was scraped""" diff --git a/src/brand/dev/types/brand_web_scrape_md_params.py b/src/brand/dev/types/brand_web_scrape_md_params.py new file mode 100644 index 0000000..5fc8732 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_md_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["BrandWebScrapeMdParams"] + + +class BrandWebScrapeMdParams(TypedDict, total=False): + url: Required[str] + """ + Full URL to scrape and convert to markdown (must include http:// or https:// + protocol) + """ + + include_images: Annotated[bool, PropertyInfo(alias="includeImages")] + """Include image references in Markdown output""" + + include_links: Annotated[bool, PropertyInfo(alias="includeLinks")] + """Preserve hyperlinks in Markdown output""" diff --git a/src/brand/dev/types/brand_web_scrape_md_response.py b/src/brand/dev/types/brand_web_scrape_md_response.py new file mode 100644 index 0000000..5161243 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_md_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["BrandWebScrapeMdResponse"] + + +class BrandWebScrapeMdResponse(BaseModel): + markdown: str + """Page content converted to GitHub Flavored Markdown""" + + success: Literal[True] + """Indicates success""" + + url: str + """The URL that was scraped""" diff --git a/src/brand/dev/types/brand_web_scrape_sitemap_params.py b/src/brand/dev/types/brand_web_scrape_sitemap_params.py new file mode 100644 index 0000000..a250097 --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_sitemap_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrandWebScrapeSitemapParams"] + + +class BrandWebScrapeSitemapParams(TypedDict, total=False): + domain: Required[str] + """Domain name to crawl sitemaps for (e.g., 'example.com'). + + The domain will be automatically normalized and validated. + """ diff --git a/src/brand/dev/types/brand_web_scrape_sitemap_response.py b/src/brand/dev/types/brand_web_scrape_sitemap_response.py new file mode 100644 index 0000000..ae7562e --- /dev/null +++ b/src/brand/dev/types/brand_web_scrape_sitemap_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["BrandWebScrapeSitemapResponse", "Meta"] + + +class Meta(BaseModel): + """Metadata about the sitemap crawl operation""" + + errors: int + """Number of errors encountered during crawling""" + + sitemaps_discovered: int = FieldInfo(alias="sitemapsDiscovered") + """Total number of sitemap files discovered""" + + sitemaps_fetched: int = FieldInfo(alias="sitemapsFetched") + """Number of sitemap files successfully fetched and parsed""" + + sitemaps_skipped: int = FieldInfo(alias="sitemapsSkipped") + """Number of sitemap files skipped (due to errors, timeouts, or limits)""" + + +class BrandWebScrapeSitemapResponse(BaseModel): + domain: str + """The normalized domain that was crawled""" + + meta: Meta + """Metadata about the sitemap crawl operation""" + + success: Literal[True] + """Indicates success""" + + urls: List[str] + """Array of discovered page URLs from the sitemap (max 500)""" diff --git a/tests/api_resources/test_brand.py b/tests/api_resources/test_brand.py index 385ced6..4f86fcc 100644 --- a/tests/api_resources/test_brand.py +++ b/tests/api_resources/test_brand.py @@ -18,12 +18,16 @@ BrandAIProductsResponse, BrandScreenshotResponse, BrandStyleguideResponse, + BrandWebScrapeMdResponse, BrandRetrieveNaicsResponse, + BrandWebScrapeHTMLResponse, BrandRetrieveByIsinResponse, BrandRetrieveByNameResponse, BrandPrefetchByEmailResponse, BrandRetrieveByEmailResponse, + BrandWebScrapeImagesResponse, BrandRetrieveByTickerResponse, + BrandWebScrapeSitemapResponse, BrandRetrieveSimplifiedResponse, BrandIdentifyFromTransactionResponse, ) @@ -837,6 +841,152 @@ def test_streaming_response_styleguide(self, client: BrandDev) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_html(self, client: BrandDev) -> None: + brand = client.brand.web_scrape_html( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_web_scrape_html(self, client: BrandDev) -> None: + response = client.brand.with_raw_response.web_scrape_html( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = response.parse() + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_web_scrape_html(self, client: BrandDev) -> None: + with client.brand.with_streaming_response.web_scrape_html( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = response.parse() + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_images(self, client: BrandDev) -> None: + brand = client.brand.web_scrape_images( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_web_scrape_images(self, client: BrandDev) -> None: + response = client.brand.with_raw_response.web_scrape_images( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = response.parse() + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_web_scrape_images(self, client: BrandDev) -> None: + with client.brand.with_streaming_response.web_scrape_images( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = response.parse() + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_md(self, client: BrandDev) -> None: + brand = client.brand.web_scrape_md( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_md_with_all_params(self, client: BrandDev) -> None: + brand = client.brand.web_scrape_md( + url="https://example.com", + include_images=True, + include_links=True, + ) + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_web_scrape_md(self, client: BrandDev) -> None: + response = client.brand.with_raw_response.web_scrape_md( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = response.parse() + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_web_scrape_md(self, client: BrandDev) -> None: + with client.brand.with_streaming_response.web_scrape_md( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = response.parse() + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_web_scrape_sitemap(self, client: BrandDev) -> None: + brand = client.brand.web_scrape_sitemap( + domain="domain", + ) + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_web_scrape_sitemap(self, client: BrandDev) -> None: + response = client.brand.with_raw_response.web_scrape_sitemap( + domain="domain", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = response.parse() + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_web_scrape_sitemap(self, client: BrandDev) -> None: + with client.brand.with_streaming_response.web_scrape_sitemap( + domain="domain", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = response.parse() + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncBrand: parametrize = pytest.mark.parametrize( @@ -1645,3 +1795,149 @@ async def test_streaming_response_styleguide(self, async_client: AsyncBrandDev) assert_matches_type(BrandStyleguideResponse, brand, path=["response"]) assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_html(self, async_client: AsyncBrandDev) -> None: + brand = await async_client.brand.web_scrape_html( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_web_scrape_html(self, async_client: AsyncBrandDev) -> None: + response = await async_client.brand.with_raw_response.web_scrape_html( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = await response.parse() + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_web_scrape_html(self, async_client: AsyncBrandDev) -> None: + async with async_client.brand.with_streaming_response.web_scrape_html( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = await response.parse() + assert_matches_type(BrandWebScrapeHTMLResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_images(self, async_client: AsyncBrandDev) -> None: + brand = await async_client.brand.web_scrape_images( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_web_scrape_images(self, async_client: AsyncBrandDev) -> None: + response = await async_client.brand.with_raw_response.web_scrape_images( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = await response.parse() + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_web_scrape_images(self, async_client: AsyncBrandDev) -> None: + async with async_client.brand.with_streaming_response.web_scrape_images( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = await response.parse() + assert_matches_type(BrandWebScrapeImagesResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_md(self, async_client: AsyncBrandDev) -> None: + brand = await async_client.brand.web_scrape_md( + url="https://example.com", + ) + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_md_with_all_params(self, async_client: AsyncBrandDev) -> None: + brand = await async_client.brand.web_scrape_md( + url="https://example.com", + include_images=True, + include_links=True, + ) + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_web_scrape_md(self, async_client: AsyncBrandDev) -> None: + response = await async_client.brand.with_raw_response.web_scrape_md( + url="https://example.com", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = await response.parse() + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_web_scrape_md(self, async_client: AsyncBrandDev) -> None: + async with async_client.brand.with_streaming_response.web_scrape_md( + url="https://example.com", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = await response.parse() + assert_matches_type(BrandWebScrapeMdResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_web_scrape_sitemap(self, async_client: AsyncBrandDev) -> None: + brand = await async_client.brand.web_scrape_sitemap( + domain="domain", + ) + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_web_scrape_sitemap(self, async_client: AsyncBrandDev) -> None: + response = await async_client.brand.with_raw_response.web_scrape_sitemap( + domain="domain", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + brand = await response.parse() + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_web_scrape_sitemap(self, async_client: AsyncBrandDev) -> None: + async with async_client.brand.with_streaming_response.web_scrape_sitemap( + domain="domain", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + brand = await response.parse() + assert_matches_type(BrandWebScrapeSitemapResponse, brand, path=["response"]) + + assert cast(Any, response.is_closed) is True