diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..f0a5b3c --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,31 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to PyPI in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/CASParser/cas-parser-python/actions/workflows/publish-pypi.yml +name: Publish PyPI +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Publish to PyPI + run: | + bash ./bin/publish-pypi + env: + PYPI_TOKEN: ${{ secrets.CAS_PARSER_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..ea04f96 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,21 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'CASParser/cas-parser-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + PYPI_TOKEN: ${{ secrets.CAS_PARSER_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..fea3454 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.0.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index b0bed10..ff342c7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 5 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/cas-parser%2Fcas-parser-b7fdba3d3f97c7debc22c7ca30b828bce81bcd64648df8c94029b27a3321ebb9.yml openapi_spec_hash: 03f1315f1d32ada42445ca920f047dff -config_hash: 2632d49bed76591e5ca0ddf94f518f17 +config_hash: a09a453fc58f48d89b5b8fce49bfb354 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..46faeb4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +## 1.0.0 (2025-08-18) + +Full Changelog: [v0.0.1...v1.0.0](https://github.com/CASParser/cas-parser-python/compare/v0.0.1...v1.0.0) + +### Features + +* **api:** manual updates ([635bd26](https://github.com/CASParser/cas-parser-python/commit/635bd26431623f00d3af06a3256c2b7085c83487)) + + +### Chores + +* configure new SDK language ([5748dab](https://github.com/CASParser/cas-parser-python/commit/5748dab8b8241dc537456d9b8c1dae3c0e4a5d5a)) +* update SDK settings ([13b5c47](https://github.com/CASParser/cas-parser-python/commit/13b5c470a31ac72d95078236e0e16b76e753939e)) +* update SDK settings ([25126eb](https://github.com/CASParser/cas-parser-python/commit/25126eb2330f0e84bd4dd9e814e6a2e5b2ebbddc)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c565215..9de374b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,7 +62,7 @@ If you’d like to use the repository from source, you can either install from g To install via git: ```sh -$ pip install git+ssh://git@github.com/stainless-sdks/cas-parser-python.git +$ pip install git+ssh://git@github.com/CASParser/cas-parser-python.git ``` Alternatively, you can build from source and install the wheel file: @@ -120,7 +120,7 @@ the changes aren't made through the automated pipeline, you may want to make rel ### Publish with a GitHub workflow -You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/stainless-sdks/cas-parser-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. +You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/CASParser/cas-parser-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. ### Publish manually diff --git a/README.md b/README.md index 0843fd6..933b01b 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,10 @@ The REST API documentation can be found on [docs.casparser.in](https://docs.casp ## Installation ```sh -# install from this staging repo -pip install git+ssh://git@github.com/stainless-sdks/cas-parser-python.git +# install from PyPI +pip install cas_parser ``` -> [!NOTE] -> Once this package is [published to PyPI](https://www.stainless.com/docs/guides/publish), this will become: `pip install cas_parser` - ## Usage The full API of this library can be found in [api.md](api.md). @@ -33,11 +30,12 @@ from cas_parser import CasParser client = CasParser( api_key=os.environ.get("CAS_PARSER_API_KEY"), # This is the default and can be omitted - # defaults to "production". - environment="local", ) -unified_response = client.cas_parser.cams_kfintech() +unified_response = client.cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://your-cas-pdf-url-here.com", +) print(unified_response.demat_accounts) ``` @@ -57,13 +55,14 @@ from cas_parser import AsyncCasParser client = AsyncCasParser( api_key=os.environ.get("CAS_PARSER_API_KEY"), # This is the default and can be omitted - # defaults to "production". - environment="local", ) async def main() -> None: - unified_response = await client.cas_parser.cams_kfintech() + unified_response = await client.cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://your-cas-pdf-url-here.com", + ) print(unified_response.demat_accounts) @@ -79,8 +78,8 @@ By default, the async client uses `httpx` for HTTP requests. However, for improv You can enable this by installing `aiohttp`: ```sh -# install from this staging repo -pip install 'cas_parser[aiohttp] @ git+ssh://git@github.com/stainless-sdks/cas-parser-python.git' +# install from PyPI +pip install cas_parser[aiohttp] ``` Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: @@ -96,7 +95,10 @@ async def main() -> None: api_key="My API Key", http_client=DefaultAioHttpClient(), ) as client: - unified_response = await client.cas_parser.cams_kfintech() + unified_response = await client.cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://your-cas-pdf-url-here.com", + ) print(unified_response.demat_accounts) @@ -128,7 +130,10 @@ from cas_parser import CasParser client = CasParser() try: - client.cas_parser.cams_kfintech() + client.cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://you-cas-pdf-url-here.com", + ) except cas_parser.APIConnectionError as e: print("The server could not be reached") print(e.__cause__) # an underlying Exception, likely raised within httpx. @@ -171,7 +176,10 @@ client = CasParser( ) # Or, configure per-request: -client.with_options(max_retries=5).cas_parser.cams_kfintech() +client.with_options(max_retries=5).cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://you-cas-pdf-url-here.com", +) ``` ### Timeouts @@ -194,7 +202,10 @@ client = CasParser( ) # Override per-request: -client.with_options(timeout=5.0).cas_parser.cams_kfintech() +client.with_options(timeout=5.0).cas_parser.smart_parse( + password="ABCDF", + pdf_url="https://you-cas-pdf-url-here.com", +) ``` On timeout, an `APITimeoutError` is thrown. @@ -235,16 +246,19 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to from cas_parser import CasParser client = CasParser() -response = client.cas_parser.with_raw_response.cams_kfintech() +response = client.cas_parser.with_raw_response.smart_parse( + password="ABCDF", + pdf_url="https://you-cas-pdf-url-here.com", +) print(response.headers.get('X-My-Header')) -cas_parser = response.parse() # get the object that `cas_parser.cams_kfintech()` would have returned +cas_parser = response.parse() # get the object that `cas_parser.smart_parse()` would have returned print(cas_parser.demat_accounts) ``` -These methods return an [`APIResponse`](https://github.com/stainless-sdks/cas-parser-python/tree/main/src/cas_parser/_response.py) object. +These methods return an [`APIResponse`](https://github.com/CASParser/cas-parser-python/tree/main/src/cas_parser/_response.py) object. -The async client returns an [`AsyncAPIResponse`](https://github.com/stainless-sdks/cas-parser-python/tree/main/src/cas_parser/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. +The async client returns an [`AsyncAPIResponse`](https://github.com/CASParser/cas-parser-python/tree/main/src/cas_parser/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. #### `.with_streaming_response` @@ -253,7 +267,10 @@ The above interface eagerly reads the full response body when you make the reque To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. ```python -with client.cas_parser.with_streaming_response.cams_kfintech() as response: +with client.cas_parser.with_streaming_response.smart_parse( + password="ABCDF", + pdf_url="https://you-cas-pdf-url-here.com", +) as response: print(response.headers.get("X-My-Header")) for line in response.iter_lines(): @@ -348,7 +365,7 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. -We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/cas-parser-python/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/CASParser/cas-parser-python/issues) with questions, bugs, or suggestions. ### Determining the installed version diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..b845b0f --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${PYPI_TOKEN}" ]; then + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/pyproject.toml b/pyproject.toml index 2c2af13..df5dc8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cas_parser" -version = "0.0.1" +version = "1.0.0" description = "The official Python library for the CAS Parser API" dynamic = ["readme"] license = "Apache-2.0" @@ -35,8 +35,8 @@ classifiers = [ ] [project.urls] -Homepage = "https://github.com/stainless-sdks/cas-parser-python" -Repository = "https://github.com/stainless-sdks/cas-parser-python" +Homepage = "https://github.com/CASParser/cas-parser-python" +Repository = "https://github.com/CASParser/cas-parser-python" [project.optional-dependencies] aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] @@ -125,7 +125,7 @@ path = "README.md" [[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] # replace relative links with absolute links pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' -replacement = '[\1](https://github.com/stainless-sdks/cas-parser-python/tree/main/\g<2>)' +replacement = '[\1](https://github.com/CASParser/cas-parser-python/tree/main/\g<2>)' [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..316db21 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,66 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "python", + "extra-files": [ + "src/cas_parser/_version.py" + ] +} \ No newline at end of file diff --git a/src/cas_parser/__init__.py b/src/cas_parser/__init__.py index 25d271f..a6c342f 100644 --- a/src/cas_parser/__init__.py +++ b/src/cas_parser/__init__.py @@ -6,7 +6,6 @@ from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path from ._client import ( - ENVIRONMENTS, Client, Stream, Timeout, @@ -72,7 +71,6 @@ "AsyncStream", "CasParser", "AsyncCasParser", - "ENVIRONMENTS", "file_from_path", "BaseModel", "DEFAULT_TIMEOUT", diff --git a/src/cas_parser/_client.py b/src/cas_parser/_client.py index 2bd3fc9..27572c6 100644 --- a/src/cas_parser/_client.py +++ b/src/cas_parser/_client.py @@ -3,8 +3,8 @@ from __future__ import annotations import os -from typing import Any, Dict, Union, Mapping, cast -from typing_extensions import Self, Literal, override +from typing import Any, Union, Mapping +from typing_extensions import Self, override import httpx @@ -31,7 +31,6 @@ ) __all__ = [ - "ENVIRONMENTS", "Timeout", "Transport", "ProxiesTypes", @@ -42,11 +41,6 @@ "AsyncClient", ] -ENVIRONMENTS: Dict[str, str] = { - "production": "https://portfolio-parser.api.casparser.in", - "local": "http://localhost:5000", -} - class CasParser(SyncAPIClient): cas_parser: cas_parser.CasParserResource @@ -57,14 +51,11 @@ class CasParser(SyncAPIClient): # client options api_key: str - _environment: Literal["production", "local"] | NotGiven - def __init__( self, *, api_key: str | None = None, - environment: Literal["production", "local"] | NotGiven = NOT_GIVEN, - base_url: str | httpx.URL | None | NotGiven = NOT_GIVEN, + base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -95,31 +86,10 @@ def __init__( ) self.api_key = api_key - self._environment = environment - - base_url_env = os.environ.get("CAS_PARSER_BASE_URL") - if is_given(base_url) and base_url is not None: - # cast required because mypy doesn't understand the type narrowing - base_url = cast("str | httpx.URL", base_url) # pyright: ignore[reportUnnecessaryCast] - elif is_given(environment): - if base_url_env and base_url is not None: - raise ValueError( - "Ambiguous URL; The `CAS_PARSER_BASE_URL` env var and the `environment` argument are given. If you want to use the environment, you must pass base_url=None", - ) - - try: - base_url = ENVIRONMENTS[environment] - except KeyError as exc: - raise ValueError(f"Unknown environment: {environment}") from exc - elif base_url_env is not None: - base_url = base_url_env - else: - self._environment = environment = "production" - - try: - base_url = ENVIRONMENTS[environment] - except KeyError as exc: - raise ValueError(f"Unknown environment: {environment}") from exc + if base_url is None: + base_url = os.environ.get("CAS_PARSER_BASE_URL") + if base_url is None: + base_url = f"https://portfolio-parser.api.casparser.in" super().__init__( version=__version__, @@ -161,7 +131,6 @@ def copy( self, *, api_key: str | None = None, - environment: Literal["production", "local"] | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.Client | None = None, @@ -197,7 +166,6 @@ def copy( return self.__class__( api_key=api_key or self.api_key, base_url=base_url or self.base_url, - environment=environment or self._environment, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, max_retries=max_retries if is_given(max_retries) else self.max_retries, @@ -253,14 +221,11 @@ class AsyncCasParser(AsyncAPIClient): # client options api_key: str - _environment: Literal["production", "local"] | NotGiven - def __init__( self, *, api_key: str | None = None, - environment: Literal["production", "local"] | NotGiven = NOT_GIVEN, - base_url: str | httpx.URL | None | NotGiven = NOT_GIVEN, + base_url: str | httpx.URL | None = None, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -291,31 +256,10 @@ def __init__( ) self.api_key = api_key - self._environment = environment - - base_url_env = os.environ.get("CAS_PARSER_BASE_URL") - if is_given(base_url) and base_url is not None: - # cast required because mypy doesn't understand the type narrowing - base_url = cast("str | httpx.URL", base_url) # pyright: ignore[reportUnnecessaryCast] - elif is_given(environment): - if base_url_env and base_url is not None: - raise ValueError( - "Ambiguous URL; The `CAS_PARSER_BASE_URL` env var and the `environment` argument are given. If you want to use the environment, you must pass base_url=None", - ) - - try: - base_url = ENVIRONMENTS[environment] - except KeyError as exc: - raise ValueError(f"Unknown environment: {environment}") from exc - elif base_url_env is not None: - base_url = base_url_env - else: - self._environment = environment = "production" - - try: - base_url = ENVIRONMENTS[environment] - except KeyError as exc: - raise ValueError(f"Unknown environment: {environment}") from exc + if base_url is None: + base_url = os.environ.get("CAS_PARSER_BASE_URL") + if base_url is None: + base_url = f"https://portfolio-parser.api.casparser.in" super().__init__( version=__version__, @@ -357,7 +301,6 @@ def copy( self, *, api_key: str | None = None, - environment: Literal["production", "local"] | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.AsyncClient | None = None, @@ -393,7 +336,6 @@ def copy( return self.__class__( api_key=api_key or self.api_key, base_url=base_url or self.base_url, - environment=environment or self._environment, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, max_retries=max_retries if is_given(max_retries) else self.max_retries, diff --git a/src/cas_parser/_version.py b/src/cas_parser/_version.py index 96a609e..6e734e4 100644 --- a/src/cas_parser/_version.py +++ b/src/cas_parser/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "cas_parser" -__version__ = "0.0.1" +__version__ = "1.0.0" # x-release-please-version diff --git a/src/cas_parser/resources/cas_generator.py b/src/cas_parser/resources/cas_generator.py index 77bc291..511b893 100644 --- a/src/cas_parser/resources/cas_generator.py +++ b/src/cas_parser/resources/cas_generator.py @@ -30,7 +30,7 @@ def with_raw_response(self) -> CasGeneratorResourceWithRawResponse: This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers """ return CasGeneratorResourceWithRawResponse(self) @@ -39,7 +39,7 @@ def with_streaming_response(self) -> CasGeneratorResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#with_streaming_response + For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response """ return CasGeneratorResourceWithStreamingResponse(self) @@ -113,7 +113,7 @@ def with_raw_response(self) -> AsyncCasGeneratorResourceWithRawResponse: This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers """ return AsyncCasGeneratorResourceWithRawResponse(self) @@ -122,7 +122,7 @@ def with_streaming_response(self) -> AsyncCasGeneratorResourceWithStreamingRespo """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#with_streaming_response + For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response """ return AsyncCasGeneratorResourceWithStreamingResponse(self) diff --git a/src/cas_parser/resources/cas_parser.py b/src/cas_parser/resources/cas_parser.py index 45d205a..a64b7dd 100644 --- a/src/cas_parser/resources/cas_parser.py +++ b/src/cas_parser/resources/cas_parser.py @@ -35,7 +35,7 @@ def with_raw_response(self) -> CasParserResourceWithRawResponse: This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers """ return CasParserResourceWithRawResponse(self) @@ -44,7 +44,7 @@ def with_streaming_response(self) -> CasParserResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#with_streaming_response + For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response """ return CasParserResourceWithStreamingResponse(self) @@ -281,7 +281,7 @@ def with_raw_response(self) -> AsyncCasParserResourceWithRawResponse: This property can be used as a prefix for any HTTP method call to return the raw response object instead of the parsed content. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/CASParser/cas-parser-python#accessing-raw-response-data-eg-headers """ return AsyncCasParserResourceWithRawResponse(self) @@ -290,7 +290,7 @@ def with_streaming_response(self) -> AsyncCasParserResourceWithStreamingResponse """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/cas-parser-python#with_streaming_response + For more information, see https://www.github.com/CASParser/cas-parser-python#with_streaming_response """ return AsyncCasParserResourceWithStreamingResponse(self) diff --git a/tests/test_client.py b/tests/test_client.py index 5b83c72..201c609 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -560,16 +560,6 @@ def test_base_url_env(self) -> None: client = CasParser(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" - # explicit environment arg requires explicitness - with update_env(CAS_PARSER_BASE_URL="http://localhost:5000/from/env"): - with pytest.raises(ValueError, match=r"you must pass base_url=None"): - CasParser(api_key=api_key, _strict_response_validation=True, environment="production") - - client = CasParser( - base_url=None, api_key=api_key, _strict_response_validation=True, environment="production" - ) - assert str(client.base_url).startswith("https://portfolio-parser.api.casparser.in") - @pytest.mark.parametrize( "client", [ @@ -724,20 +714,20 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @mock.patch("cas_parser._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: CasParser) -> None: - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=httpx.TimeoutException("Test timeout error")) + respx_mock.post("/v4/smart/parse").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - client.cas_parser.with_streaming_response.cams_kfintech().__enter__() + client.cas_parser.with_streaming_response.smart_parse().__enter__() assert _get_open_connections(self.client) == 0 @mock.patch("cas_parser._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: CasParser) -> None: - respx_mock.post("/v4/cams_kfintech/parse").mock(return_value=httpx.Response(500)) + respx_mock.post("/v4/smart/parse").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - client.cas_parser.with_streaming_response.cams_kfintech().__enter__() + client.cas_parser.with_streaming_response.smart_parse().__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -764,9 +754,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = client.cas_parser.with_raw_response.cams_kfintech() + response = client.cas_parser.with_raw_response.smart_parse() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -788,9 +778,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = client.cas_parser.with_raw_response.cams_kfintech(extra_headers={"x-stainless-retry-count": Omit()}) + response = client.cas_parser.with_raw_response.smart_parse(extra_headers={"x-stainless-retry-count": Omit()}) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -811,9 +801,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = client.cas_parser.with_raw_response.cams_kfintech(extra_headers={"x-stainless-retry-count": "42"}) + response = client.cas_parser.with_raw_response.smart_parse(extra_headers={"x-stainless-retry-count": "42"}) assert response.http_request.headers.get("x-stainless-retry-count") == "42" @@ -1373,16 +1363,6 @@ def test_base_url_env(self) -> None: client = AsyncCasParser(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" - # explicit environment arg requires explicitness - with update_env(CAS_PARSER_BASE_URL="http://localhost:5000/from/env"): - with pytest.raises(ValueError, match=r"you must pass base_url=None"): - AsyncCasParser(api_key=api_key, _strict_response_validation=True, environment="production") - - client = AsyncCasParser( - base_url=None, api_key=api_key, _strict_response_validation=True, environment="production" - ) - assert str(client.base_url).startswith("https://portfolio-parser.api.casparser.in") - @pytest.mark.parametrize( "client", [ @@ -1551,10 +1531,10 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte async def test_retrying_timeout_errors_doesnt_leak( self, respx_mock: MockRouter, async_client: AsyncCasParser ) -> None: - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=httpx.TimeoutException("Test timeout error")) + respx_mock.post("/v4/smart/parse").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await async_client.cas_parser.with_streaming_response.cams_kfintech().__aenter__() + await async_client.cas_parser.with_streaming_response.smart_parse().__aenter__() assert _get_open_connections(self.client) == 0 @@ -1563,10 +1543,10 @@ async def test_retrying_timeout_errors_doesnt_leak( async def test_retrying_status_errors_doesnt_leak( self, respx_mock: MockRouter, async_client: AsyncCasParser ) -> None: - respx_mock.post("/v4/cams_kfintech/parse").mock(return_value=httpx.Response(500)) + respx_mock.post("/v4/smart/parse").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await async_client.cas_parser.with_streaming_response.cams_kfintech().__aenter__() + await async_client.cas_parser.with_streaming_response.smart_parse().__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1594,9 +1574,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = await client.cas_parser.with_raw_response.cams_kfintech() + response = await client.cas_parser.with_raw_response.smart_parse() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -1619,9 +1599,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = await client.cas_parser.with_raw_response.cams_kfintech( + response = await client.cas_parser.with_raw_response.smart_parse( extra_headers={"x-stainless-retry-count": Omit()} ) @@ -1645,9 +1625,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: return httpx.Response(500) return httpx.Response(200) - respx_mock.post("/v4/cams_kfintech/parse").mock(side_effect=retry_handler) + respx_mock.post("/v4/smart/parse").mock(side_effect=retry_handler) - response = await client.cas_parser.with_raw_response.cams_kfintech( + response = await client.cas_parser.with_raw_response.smart_parse( extra_headers={"x-stainless-retry-count": "42"} )