diff --git a/.fern/metadata.json b/.fern/metadata.json index 442a337..ea7f32b 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -10,9 +10,9 @@ "exported_filename": "pipedream.py" } }, - "originGitCommit": "b399bbbdcc0ed7ed414d0fcc795c5c6b6dea46eb", + "originGitCommit": "267ec323a4305eba2c41bd93e26686a26e329107", "originGitCommitIsDirty": false, "invokedBy": "ci", "ciProvider": "github", - "sdkVersion": "2.0.1" + "sdkVersion": "2.0.2" } \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index a5e8d30..50b8d79 100644 --- a/poetry.lock +++ b/poetry.lock @@ -496,13 +496,13 @@ httpx = ">=0.27.0" [[package]] name = "idna" -version = "3.13" +version = "3.15" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" files = [ - {file = "idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3"}, - {file = "idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242"}, + {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, + {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, ] [package.extras] diff --git a/pyproject.toml b/pyproject.toml index 9afae7b..319ed2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "pipedream" -version = "2.0.1" +version = "2.0.2" description = "" readme = "README.md" authors = [] diff --git a/src/pipedream/accounts/client.py b/src/pipedream/accounts/client.py index df8e7d5..9399c45 100644 --- a/src/pipedream/accounts/client.py +++ b/src/pipedream/accounts/client.py @@ -288,6 +288,53 @@ def delete_by_app(self, app_id: str, *, request_options: typing.Optional[Request _response = self._raw_client.delete_by_app(app_id, request_options=request_options) return _response.data + def list_by_external_user( + self, + external_user_id: str, + *, + include_credentials: typing.Optional[bool] = None, + app: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Account]: + """ + List all connected accounts for a specific external user. Equivalent to GET /accounts with external_user_id filter but uses path-based routing. + + Parameters + ---------- + external_user_id : str + + include_credentials : typing.Optional[bool] + + app : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Account] + accounts listed + + Examples + -------- + from pipedream import Pipedream + + client = Pipedream( + project_id="YOUR_PROJECT_ID", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + client.accounts.list_by_external_user( + external_user_id="external_user_id", + include_credentials=True, + app="app", + ) + """ + _response = self._raw_client.list_by_external_user( + external_user_id, include_credentials=include_credentials, app=app, request_options=request_options + ) + return _response.data + class AsyncAccountsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -604,3 +651,58 @@ async def main() -> None: """ _response = await self._raw_client.delete_by_app(app_id, request_options=request_options) return _response.data + + async def list_by_external_user( + self, + external_user_id: str, + *, + include_credentials: typing.Optional[bool] = None, + app: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> typing.List[Account]: + """ + List all connected accounts for a specific external user. Equivalent to GET /accounts with external_user_id filter but uses path-based routing. + + Parameters + ---------- + external_user_id : str + + include_credentials : typing.Optional[bool] + + app : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + typing.List[Account] + accounts listed + + Examples + -------- + import asyncio + + from pipedream import AsyncPipedream + + client = AsyncPipedream( + project_id="YOUR_PROJECT_ID", + client_id="YOUR_CLIENT_ID", + client_secret="YOUR_CLIENT_SECRET", + ) + + + async def main() -> None: + await client.accounts.list_by_external_user( + external_user_id="external_user_id", + include_credentials=True, + app="app", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_by_external_user( + external_user_id, include_credentials=include_credentials, app=app, request_options=request_options + ) + return _response.data diff --git a/src/pipedream/accounts/raw_client.py b/src/pipedream/accounts/raw_client.py index 978f1f7..1550daa 100644 --- a/src/pipedream/accounts/raw_client.py +++ b/src/pipedream/accounts/raw_client.py @@ -375,6 +375,72 @@ def delete_by_app( ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + def list_by_external_user( + self, + external_user_id: str, + *, + include_credentials: typing.Optional[bool] = None, + app: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[typing.List[Account]]: + """ + List all connected accounts for a specific external user. Equivalent to GET /accounts with external_user_id filter but uses path-based routing. + + Parameters + ---------- + external_user_id : str + + include_credentials : typing.Optional[bool] + + app : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[typing.List[Account]] + accounts listed + """ + _response = self._client_wrapper.httpx_client.request( + f"v1/connect/{encode_path_param(self._client_wrapper._project_id)}/users/{encode_path_param(external_user_id)}/accounts", + method="GET", + params={ + "include_credentials": include_credentials, + "app": app, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Account], + parse_obj_as( + type_=typing.List[Account], # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + class AsyncRawAccountsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -735,3 +801,69 @@ async def delete_by_app( status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def list_by_external_user( + self, + external_user_id: str, + *, + include_credentials: typing.Optional[bool] = None, + app: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[typing.List[Account]]: + """ + List all connected accounts for a specific external user. Equivalent to GET /accounts with external_user_id filter but uses path-based routing. + + Parameters + ---------- + external_user_id : str + + include_credentials : typing.Optional[bool] + + app : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[typing.List[Account]] + accounts listed + """ + _response = await self._client_wrapper.httpx_client.request( + f"v1/connect/{encode_path_param(self._client_wrapper._project_id)}/users/{encode_path_param(external_user_id)}/accounts", + method="GET", + params={ + "include_credentials": include_credentials, + "app": app, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + typing.List[Account], + parse_obj_as( + type_=typing.List[Account], # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/pipedream/core/client_wrapper.py b/src/pipedream/core/client_wrapper.py index 344b013..2921319 100644 --- a/src/pipedream/core/client_wrapper.py +++ b/src/pipedream/core/client_wrapper.py @@ -34,12 +34,12 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "pipedream/2.0.1", + "User-Agent": "pipedream/2.0.2", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "pipedream", - "X-Fern-SDK-Version": "2.0.1", + "X-Fern-SDK-Version": "2.0.2", **(self.get_custom_headers() or {}), } if self._project_environment is not None: