pyalexatodo.api
1from http import HTTPMethod 2from typing import TYPE_CHECKING 3 4from aioamazondevices.api import AmazonEchoApi 5 6from pyalexatodo.exceptions import ItemNotFoundException 7from pyalexatodo.models.list_info import ListInfo 8from pyalexatodo.models.list_response import ListResponse 9from pyalexatodo.models.list_item_status import ListItemStatus 10from pyalexatodo.models.list_items_response import ListItem, ListItemsResponse 11 12if TYPE_CHECKING: 13 from aiohttp import ClientResponse 14 15 16class AlexaToDoAPI: 17 """A client for interacting with Amazon Alexa shopping lists. 18 19 This class provides methods to manage Alexa shopping lists, including: 20 - Fetching lists and list items 21 - Adding, removing, and updating items 22 - Managing item status (checked/unchecked) 23 24 All methods are asynchronous and require an active AmazonEchoApi login session. 25 """ 26 def __init__(self, alexa_echo_api: AmazonEchoApi, base_url: str | None = None): 27 """Initialize the Alexa List API client. 28 29 Args: 30 alexa_echo_api: An authenticated AmazonEchoApi instance. 31 base_url: Base URL for API requests (for testing). If None, uses Amazon's URL. 32 """ 33 self.alexa_echo_api = alexa_echo_api 34 """AmazonEchoAPI instance used for making authenticated requests to the Alexa API.""" 35 36 self._domain_extension = alexa_echo_api.domain 37 self._base_url = base_url or f"https://www.amazon.{self._domain_extension}" 38 39 async def _http_request( 40 self, method: HTTPMethod, url: str, data: dict 41 ) -> "ClientResponse": 42 """ 43 Make an HTTP request to the Alexa API. 44 45 Args: 46 method: The HTTP method to use (GET, POST, PUT, DELETE, etc.). 47 url: The URL endpoint to request. 48 data: The request data to be sent as JSON. 49 50 Returns: 51 The response object from the HTTP request. 52 """ 53 _, response = await self.alexa_echo_api._http_wrapper.session_request( 54 method=method, url=url, input_data=data, json_data=True, 55 ) 56 57 return response 58 59 async def get_lists(self) -> ListInfo[ListInfo]: 60 """Fetch all available Alexa shopping lists. 61 62 Returns: 63 A list of shopping list information objects. 64 65 Raises: 66 Exception: If the API request fails. 67 """ 68 result = await self._http_request( 69 HTTPMethod.POST, 70 f"{self._base_url}/alexashoppinglists/api/v2/lists/fetch", 71 {}, 72 ) 73 74 if not result or result.status != 200: 75 raise Exception("Failed to fetch lists") 76 77 result_json = await result.json() 78 list_infos = ListResponse(**result_json) 79 80 return list_infos.listInfoList 81 82 async def get_list_items(self, list_id: str) -> ListInfo[ListItem]: 83 """Fetch all items from a specified Alexa shopping list. 84 85 Args: 86 list_id: The ID of the list to fetch items from. 87 88 Returns: 89 A list of shopping list items. 90 91 Raises: 92 Exception: If the API request fails. 93 """ 94 result = await self._http_request( 95 HTTPMethod.POST, 96 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/fetch?limit=100", 97 {}, 98 ) 99 100 if not result or result.status != 200: 101 raise Exception(f"Failed to fetch list items for list: {list_id}") 102 103 result_json = await result.json() 104 list_items = ListItemsResponse(**result_json) 105 106 return list_items.itemInfoList 107 108 async def set_item_checked_status( 109 self, list_id: str, item_id: str, checked: bool, version: int 110 ): 111 """Update the checked status of an item in a shopping list. 112 113 Args: 114 list_id: The ID of the list containing the item. 115 item_id: The ID of the item to update. 116 checked: True to mark as complete, False to mark as active. 117 version: The current version of the item. 118 The value is included in the get_list_items response and is required by the Amazon API. 119 120 Raises: 121 Exception: If the API request fails. 122 """ 123 result = await self._http_request( 124 HTTPMethod.PUT, 125 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 126 { 127 "itemAttributesToUpdate": [ 128 { 129 "type": "itemStatus", 130 "value": ListItemStatus.COMPLETE.value 131 if checked 132 else ListItemStatus.ACTIVE.value, 133 } 134 ], 135 "itemAttributesToRemove": [], 136 }, 137 ) 138 139 if not result or result.status != 200: 140 raise Exception(f"Failed to toggle item: {item_id}") 141 142 async def add_item(self, list_id: str, name: str): 143 """Add a new item to a shopping list. 144 145 Args: 146 list_id: The ID of the list to add the item to. 147 name: The name of the item to add. 148 149 Raises: 150 Exception: If the API request fails. 151 """ 152 result = await self._http_request( 153 HTTPMethod.POST, 154 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items", 155 { 156 "items": [ 157 { 158 "itemType": "KEYWORD", 159 "itemName": name, 160 } 161 ] 162 }, 163 ) 164 165 if not result or result.status != 200: 166 raise Exception(f"Failed to add item: {name}") 167 168 async def delete_item(self, list_id: str, item_id: str, version: int): 169 """Delete an item from a shopping list. 170 171 Args: 172 list_id: The ID of the list containing the item. 173 item_id: The ID of the item to delete. 174 version: The current version of the item. 175 The value is included in the get_list_items response and is required by the Amazon API. 176 177 Raises: 178 Exception: If the API request fails. 179 """ 180 result = await self._http_request( 181 HTTPMethod.DELETE, 182 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 183 {}, 184 ) 185 186 if not result or result.status != 200: 187 raise Exception(f"Failed to delete item: {item_id}") 188 189 async def rename_item( 190 self, list_id: str, item_id: str, new_name: str, version: int 191 ): 192 """Rename an item in a shopping list. 193 194 Args: 195 list_id: The ID of the list containing the item. 196 item_id: The ID of the item to rename. 197 new_name: The new name for the item. 198 version: The current version of the item. 199 The value is included in the get_list_items response and is required by the Amazon API. 200 201 Raises: 202 Exception: If the API request fails. 203 """ 204 result = await self._http_request( 205 HTTPMethod.PUT, 206 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 207 { 208 "itemAttributesToUpdate": [{"type": "itemName", "value": new_name}], 209 "itemAttributesToRemove": [], 210 }, 211 ) 212 213 if not result or result.status != 200: 214 raise Exception(f"Failed to rename item: {item_id}") 215 216 async def get_item_by_name(self, list_id: str, name: str) -> ListItem: 217 """Find an item in a shopping list by its name. 218 219 The search is case-insensitive. If multiple items have the same name, 220 the first one found will be returned. 221 222 Args: 223 list_id: The ID of the list to search in. 224 name: The name of the item to find. 225 226 Returns: 227 The found item. 228 229 Raises: 230 ItemNotFoundException: If no item with the given name is found. 231 """ 232 list_items = await self.get_list_items(list_id) 233 for list_item in list_items: 234 if list_item.name.casefold() == name.casefold(): 235 return list_item 236 raise ItemNotFoundException
class
AlexaToDoAPI:
17class AlexaToDoAPI: 18 """A client for interacting with Amazon Alexa shopping lists. 19 20 This class provides methods to manage Alexa shopping lists, including: 21 - Fetching lists and list items 22 - Adding, removing, and updating items 23 - Managing item status (checked/unchecked) 24 25 All methods are asynchronous and require an active AmazonEchoApi login session. 26 """ 27 def __init__(self, alexa_echo_api: AmazonEchoApi, base_url: str | None = None): 28 """Initialize the Alexa List API client. 29 30 Args: 31 alexa_echo_api: An authenticated AmazonEchoApi instance. 32 base_url: Base URL for API requests (for testing). If None, uses Amazon's URL. 33 """ 34 self.alexa_echo_api = alexa_echo_api 35 """AmazonEchoAPI instance used for making authenticated requests to the Alexa API.""" 36 37 self._domain_extension = alexa_echo_api.domain 38 self._base_url = base_url or f"https://www.amazon.{self._domain_extension}" 39 40 async def _http_request( 41 self, method: HTTPMethod, url: str, data: dict 42 ) -> "ClientResponse": 43 """ 44 Make an HTTP request to the Alexa API. 45 46 Args: 47 method: The HTTP method to use (GET, POST, PUT, DELETE, etc.). 48 url: The URL endpoint to request. 49 data: The request data to be sent as JSON. 50 51 Returns: 52 The response object from the HTTP request. 53 """ 54 _, response = await self.alexa_echo_api._http_wrapper.session_request( 55 method=method, url=url, input_data=data, json_data=True, 56 ) 57 58 return response 59 60 async def get_lists(self) -> ListInfo[ListInfo]: 61 """Fetch all available Alexa shopping lists. 62 63 Returns: 64 A list of shopping list information objects. 65 66 Raises: 67 Exception: If the API request fails. 68 """ 69 result = await self._http_request( 70 HTTPMethod.POST, 71 f"{self._base_url}/alexashoppinglists/api/v2/lists/fetch", 72 {}, 73 ) 74 75 if not result or result.status != 200: 76 raise Exception("Failed to fetch lists") 77 78 result_json = await result.json() 79 list_infos = ListResponse(**result_json) 80 81 return list_infos.listInfoList 82 83 async def get_list_items(self, list_id: str) -> ListInfo[ListItem]: 84 """Fetch all items from a specified Alexa shopping list. 85 86 Args: 87 list_id: The ID of the list to fetch items from. 88 89 Returns: 90 A list of shopping list items. 91 92 Raises: 93 Exception: If the API request fails. 94 """ 95 result = await self._http_request( 96 HTTPMethod.POST, 97 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/fetch?limit=100", 98 {}, 99 ) 100 101 if not result or result.status != 200: 102 raise Exception(f"Failed to fetch list items for list: {list_id}") 103 104 result_json = await result.json() 105 list_items = ListItemsResponse(**result_json) 106 107 return list_items.itemInfoList 108 109 async def set_item_checked_status( 110 self, list_id: str, item_id: str, checked: bool, version: int 111 ): 112 """Update the checked status of an item in a shopping list. 113 114 Args: 115 list_id: The ID of the list containing the item. 116 item_id: The ID of the item to update. 117 checked: True to mark as complete, False to mark as active. 118 version: The current version of the item. 119 The value is included in the get_list_items response and is required by the Amazon API. 120 121 Raises: 122 Exception: If the API request fails. 123 """ 124 result = await self._http_request( 125 HTTPMethod.PUT, 126 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 127 { 128 "itemAttributesToUpdate": [ 129 { 130 "type": "itemStatus", 131 "value": ListItemStatus.COMPLETE.value 132 if checked 133 else ListItemStatus.ACTIVE.value, 134 } 135 ], 136 "itemAttributesToRemove": [], 137 }, 138 ) 139 140 if not result or result.status != 200: 141 raise Exception(f"Failed to toggle item: {item_id}") 142 143 async def add_item(self, list_id: str, name: str): 144 """Add a new item to a shopping list. 145 146 Args: 147 list_id: The ID of the list to add the item to. 148 name: The name of the item to add. 149 150 Raises: 151 Exception: If the API request fails. 152 """ 153 result = await self._http_request( 154 HTTPMethod.POST, 155 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items", 156 { 157 "items": [ 158 { 159 "itemType": "KEYWORD", 160 "itemName": name, 161 } 162 ] 163 }, 164 ) 165 166 if not result or result.status != 200: 167 raise Exception(f"Failed to add item: {name}") 168 169 async def delete_item(self, list_id: str, item_id: str, version: int): 170 """Delete an item from a shopping list. 171 172 Args: 173 list_id: The ID of the list containing the item. 174 item_id: The ID of the item to delete. 175 version: The current version of the item. 176 The value is included in the get_list_items response and is required by the Amazon API. 177 178 Raises: 179 Exception: If the API request fails. 180 """ 181 result = await self._http_request( 182 HTTPMethod.DELETE, 183 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 184 {}, 185 ) 186 187 if not result or result.status != 200: 188 raise Exception(f"Failed to delete item: {item_id}") 189 190 async def rename_item( 191 self, list_id: str, item_id: str, new_name: str, version: int 192 ): 193 """Rename an item in a shopping list. 194 195 Args: 196 list_id: The ID of the list containing the item. 197 item_id: The ID of the item to rename. 198 new_name: The new name for the item. 199 version: The current version of the item. 200 The value is included in the get_list_items response and is required by the Amazon API. 201 202 Raises: 203 Exception: If the API request fails. 204 """ 205 result = await self._http_request( 206 HTTPMethod.PUT, 207 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 208 { 209 "itemAttributesToUpdate": [{"type": "itemName", "value": new_name}], 210 "itemAttributesToRemove": [], 211 }, 212 ) 213 214 if not result or result.status != 200: 215 raise Exception(f"Failed to rename item: {item_id}") 216 217 async def get_item_by_name(self, list_id: str, name: str) -> ListItem: 218 """Find an item in a shopping list by its name. 219 220 The search is case-insensitive. If multiple items have the same name, 221 the first one found will be returned. 222 223 Args: 224 list_id: The ID of the list to search in. 225 name: The name of the item to find. 226 227 Returns: 228 The found item. 229 230 Raises: 231 ItemNotFoundException: If no item with the given name is found. 232 """ 233 list_items = await self.get_list_items(list_id) 234 for list_item in list_items: 235 if list_item.name.casefold() == name.casefold(): 236 return list_item 237 raise ItemNotFoundException
A client for interacting with Amazon Alexa shopping lists.
This class provides methods to manage Alexa shopping lists, including:
- Fetching lists and list items
- Adding, removing, and updating items
- Managing item status (checked/unchecked)
All methods are asynchronous and require an active AmazonEchoApi login session.
AlexaToDoAPI( alexa_echo_api: aioamazondevices.api.AmazonEchoApi, base_url: str | None = None)
27 def __init__(self, alexa_echo_api: AmazonEchoApi, base_url: str | None = None): 28 """Initialize the Alexa List API client. 29 30 Args: 31 alexa_echo_api: An authenticated AmazonEchoApi instance. 32 base_url: Base URL for API requests (for testing). If None, uses Amazon's URL. 33 """ 34 self.alexa_echo_api = alexa_echo_api 35 """AmazonEchoAPI instance used for making authenticated requests to the Alexa API.""" 36 37 self._domain_extension = alexa_echo_api.domain 38 self._base_url = base_url or f"https://www.amazon.{self._domain_extension}"
Initialize the Alexa List API client.
Arguments:
- alexa_echo_api: An authenticated AmazonEchoApi instance.
- base_url: Base URL for API requests (for testing). If None, uses Amazon's URL.
async def
get_lists(unknown):
60 async def get_lists(self) -> ListInfo[ListInfo]: 61 """Fetch all available Alexa shopping lists. 62 63 Returns: 64 A list of shopping list information objects. 65 66 Raises: 67 Exception: If the API request fails. 68 """ 69 result = await self._http_request( 70 HTTPMethod.POST, 71 f"{self._base_url}/alexashoppinglists/api/v2/lists/fetch", 72 {}, 73 ) 74 75 if not result or result.status != 200: 76 raise Exception("Failed to fetch lists") 77 78 result_json = await result.json() 79 list_infos = ListResponse(**result_json) 80 81 return list_infos.listInfoList
Fetch all available Alexa shopping lists.
Returns:
A list of shopping list information objects.
Raises:
- Exception: If the API request fails.
async def
get_list_items(unknown):
83 async def get_list_items(self, list_id: str) -> ListInfo[ListItem]: 84 """Fetch all items from a specified Alexa shopping list. 85 86 Args: 87 list_id: The ID of the list to fetch items from. 88 89 Returns: 90 A list of shopping list items. 91 92 Raises: 93 Exception: If the API request fails. 94 """ 95 result = await self._http_request( 96 HTTPMethod.POST, 97 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/fetch?limit=100", 98 {}, 99 ) 100 101 if not result or result.status != 200: 102 raise Exception(f"Failed to fetch list items for list: {list_id}") 103 104 result_json = await result.json() 105 list_items = ListItemsResponse(**result_json) 106 107 return list_items.itemInfoList
Fetch all items from a specified Alexa shopping list.
Arguments:
- list_id: The ID of the list to fetch items from.
Returns:
A list of shopping list items.
Raises:
- Exception: If the API request fails.
async def
set_item_checked_status(self, list_id: str, item_id: str, checked: bool, version: int):
109 async def set_item_checked_status( 110 self, list_id: str, item_id: str, checked: bool, version: int 111 ): 112 """Update the checked status of an item in a shopping list. 113 114 Args: 115 list_id: The ID of the list containing the item. 116 item_id: The ID of the item to update. 117 checked: True to mark as complete, False to mark as active. 118 version: The current version of the item. 119 The value is included in the get_list_items response and is required by the Amazon API. 120 121 Raises: 122 Exception: If the API request fails. 123 """ 124 result = await self._http_request( 125 HTTPMethod.PUT, 126 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 127 { 128 "itemAttributesToUpdate": [ 129 { 130 "type": "itemStatus", 131 "value": ListItemStatus.COMPLETE.value 132 if checked 133 else ListItemStatus.ACTIVE.value, 134 } 135 ], 136 "itemAttributesToRemove": [], 137 }, 138 ) 139 140 if not result or result.status != 200: 141 raise Exception(f"Failed to toggle item: {item_id}")
Update the checked status of an item in a shopping list.
Arguments:
- list_id: The ID of the list containing the item.
- item_id: The ID of the item to update.
- checked: True to mark as complete, False to mark as active.
- version: The current version of the item. The value is included in the get_list_items response and is required by the Amazon API.
Raises:
- Exception: If the API request fails.
async def
add_item(self, list_id: str, name: str):
143 async def add_item(self, list_id: str, name: str): 144 """Add a new item to a shopping list. 145 146 Args: 147 list_id: The ID of the list to add the item to. 148 name: The name of the item to add. 149 150 Raises: 151 Exception: If the API request fails. 152 """ 153 result = await self._http_request( 154 HTTPMethod.POST, 155 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items", 156 { 157 "items": [ 158 { 159 "itemType": "KEYWORD", 160 "itemName": name, 161 } 162 ] 163 }, 164 ) 165 166 if not result or result.status != 200: 167 raise Exception(f"Failed to add item: {name}")
Add a new item to a shopping list.
Arguments:
- list_id: The ID of the list to add the item to.
- name: The name of the item to add.
Raises:
- Exception: If the API request fails.
async def
delete_item(self, list_id: str, item_id: str, version: int):
169 async def delete_item(self, list_id: str, item_id: str, version: int): 170 """Delete an item from a shopping list. 171 172 Args: 173 list_id: The ID of the list containing the item. 174 item_id: The ID of the item to delete. 175 version: The current version of the item. 176 The value is included in the get_list_items response and is required by the Amazon API. 177 178 Raises: 179 Exception: If the API request fails. 180 """ 181 result = await self._http_request( 182 HTTPMethod.DELETE, 183 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 184 {}, 185 ) 186 187 if not result or result.status != 200: 188 raise Exception(f"Failed to delete item: {item_id}")
Delete an item from a shopping list.
Arguments:
- list_id: The ID of the list containing the item.
- item_id: The ID of the item to delete.
- version: The current version of the item. The value is included in the get_list_items response and is required by the Amazon API.
Raises:
- Exception: If the API request fails.
async def
rename_item(self, list_id: str, item_id: str, new_name: str, version: int):
190 async def rename_item( 191 self, list_id: str, item_id: str, new_name: str, version: int 192 ): 193 """Rename an item in a shopping list. 194 195 Args: 196 list_id: The ID of the list containing the item. 197 item_id: The ID of the item to rename. 198 new_name: The new name for the item. 199 version: The current version of the item. 200 The value is included in the get_list_items response and is required by the Amazon API. 201 202 Raises: 203 Exception: If the API request fails. 204 """ 205 result = await self._http_request( 206 HTTPMethod.PUT, 207 f"{self._base_url}/alexashoppinglists/api/v2/lists/{list_id}/items/{item_id}?version={version}", 208 { 209 "itemAttributesToUpdate": [{"type": "itemName", "value": new_name}], 210 "itemAttributesToRemove": [], 211 }, 212 ) 213 214 if not result or result.status != 200: 215 raise Exception(f"Failed to rename item: {item_id}")
Rename an item in a shopping list.
Arguments:
- list_id: The ID of the list containing the item.
- item_id: The ID of the item to rename.
- new_name: The new name for the item.
- version: The current version of the item. The value is included in the get_list_items response and is required by the Amazon API.
Raises:
- Exception: If the API request fails.
217 async def get_item_by_name(self, list_id: str, name: str) -> ListItem: 218 """Find an item in a shopping list by its name. 219 220 The search is case-insensitive. If multiple items have the same name, 221 the first one found will be returned. 222 223 Args: 224 list_id: The ID of the list to search in. 225 name: The name of the item to find. 226 227 Returns: 228 The found item. 229 230 Raises: 231 ItemNotFoundException: If no item with the given name is found. 232 """ 233 list_items = await self.get_list_items(list_id) 234 for list_item in list_items: 235 if list_item.name.casefold() == name.casefold(): 236 return list_item 237 raise ItemNotFoundException
Find an item in a shopping list by its name.
The search is case-insensitive. If multiple items have the same name, the first one found will be returned.
Arguments:
- list_id: The ID of the list to search in.
- name: The name of the item to find.
Returns:
The found item.
Raises:
- ItemNotFoundException: If no item with the given name is found.