cookidoo-api 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.1.0
4
+
5
+ Initial commit.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Cyrill Raccaud cyrill.raccaud+pypi@gmail.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,178 @@
1
+ Metadata-Version: 2.1
2
+ Name: cookidoo-api
3
+ Version: 0.1.0
4
+ Summary: Unofficial package to access Cookidoo.
5
+ Author-email: Cyrill Raccaud <cyrill.raccaud+pypi@gmail.com>
6
+ License: MIT License
7
+ Project-URL: Documentation, https://miaucl.github.io/cookidoo-api/
8
+ Project-URL: Source, https://github.com/miaucl/cookidoo-api
9
+ Project-URL: Issues, https://github.com/miaucl/cookidoo-api/issues
10
+ Keywords: cookidoo,todo,web,browser,scaping,home-assistant,iot
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Intended Audience :: Information Technology
15
+ Classifier: Topic :: System :: Monitoring
16
+ Classifier: Topic :: System :: Logging
17
+ Classifier: Topic :: System :: Systems Administration
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: aiohttp
22
+ Requires-Dist: playwright
23
+ Requires-Dist: python-dotenv
24
+
25
+ # Cookidoo API
26
+
27
+ [![PyPI version](https://badge.fury.io/py/cookidoo-api.svg)](https://pypi.org/p/cookidoo-api)
28
+
29
+ An unofficial python package to access Cookidoo.
30
+
31
+ [![Unit tests](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml)
32
+ [![Smoke test](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml)
33
+ [![Ruff](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml)
34
+ [![Mypy](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml)
35
+ [![Markdownlint](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml)
36
+
37
+ [![GitHub](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/miaucl)
38
+ [![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://patreon.com/miaucl)
39
+ [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://buymeacoffee.com/miaucl)
40
+ [![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.me/sponsormiaucl)
41
+
42
+ ## Disclaimer
43
+
44
+ The developers of this module are in no way endorsed by or affiliated with Cookidoo or Vorwerk, or any associated subsidiaries, logos or trademarks.
45
+
46
+ ## Installation
47
+
48
+ **Disclaimer: This library needs a runner (browser) to execute the calls through web automation. Make sure to have it correctly set up using one of the following options before proceeding.**
49
+
50
+ [Setup runner](https://github.com/cookidoo-api/blob/master/runners)
51
+
52
+ Once you have tested your runner, install the cookidoo library and use it with your preferred browser.
53
+
54
+ `pip install cookidoo-api`
55
+
56
+ ## Documentation
57
+
58
+ See below for usage examples. See [Exceptions](#exceptions) for API-specific exceptions and mitigation strategies for common exceptions.
59
+
60
+ ## Usage Example
61
+
62
+ The API is based on the async implementation of the library [`playwright`](https://playwright.dev/python/docs/api/class-playwright) in collaboration with a runner for browser emulation.
63
+
64
+ Make sure to have stored your credentials in the top-level file `.env` as such, to loaded by `dotenv`. Alternatively, provide the environment variables by any other `dotenv` compatible means.
65
+
66
+ ```text
67
+ EMAIL=your@mail.com
68
+ PASSWORD=password
69
+ ```
70
+
71
+ Run the [example script](https://github.com/miaucl/cookidoo-api/blob/master/example.py) and have a look at the inline comments for more explanation.
72
+
73
+ ## Exceptions
74
+
75
+ In case something goes wrong during a request, several [exceptions](https://github.com/miaucl/cookidoo/blob/master/cookidoo_api/exceptions.py) can be thrown.
76
+ They will either be
77
+
78
+ - `CookidooActionException`
79
+ - `CookidooAuthBotDetectionException`
80
+ - `CookidooAuthException`
81
+ - `CookidooConfigException`
82
+ - `CookidooNavigationException`
83
+ - `CookidooSelectorException`
84
+ - `CookidooUnavailableException`
85
+ - `CookidooUnexpectedStateException`
86
+
87
+ depending on the context. All inherit from `CookidooException`.
88
+
89
+ ### Another asyncio event loop is
90
+
91
+ With the async calls, you might encounter an error that another asyncio event loop is already running on the same thread. This is expected behavior according to the asyncio.run() [documentation](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). You cannot use more than one aiohttp session per thread, reuse the existing one!
92
+
93
+ ### Exception ignored: RuntimeError: Event loop is closed
94
+
95
+ Due to a known issue in some versions of aiohttp when using Windows, you might encounter a similar error to this:
96
+
97
+ ```python
98
+ Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000000>
99
+ Traceback (most recent call last):
100
+ File "C:\...\py38\lib\asyncio\proactor_events.py", line 116, in __del__
101
+ self.close()
102
+ File "C:\...\py38\lib\asyncio\proactor_events.py", line 108, in close
103
+ self._loop.call_soon(self._call_connection_lost, None)
104
+ File "C:\...\py38\lib\asyncio\base_events.py", line 719, in call_soon
105
+ self._check_closed()
106
+ File "C:\...\py38\lib\asyncio\base_events.py", line 508, in _check_closed
107
+ raise RuntimeError('Event loop is closed')
108
+ RuntimeError: Event loop is closed
109
+ ```
110
+
111
+ You can fix this according to [this](https://stackoverflow.com/questions/68123296/asyncio-throws-runtime-error-with-exception-ignored) StackOverflow answer by adding the following line of code before executing the library:
112
+
113
+ ```python
114
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
115
+ ```
116
+
117
+ ## Bot detection and captcha problems
118
+
119
+ There is an inbuilt bot detection on cookidoo which can block the login process. There is a clear error message, when that happens. The tokens are valid for a fixed duration and therefore the library tries to minimize the amount of logins required to avoid the captcha process. Unfortunately, this is not always possible when developing or debugging a setup, and you might run into it. To continue, either wait a day or switch to a runner with a gui and enable `captcha` mode to manually solve the captcha during the login or a service such as [`capsolver`](https://www.capsolver.com/).
120
+
121
+ It is generally advised, to first try the login in `fail` mode and only activate a recovery mode on a `CookidooAuthBotDetectionException` raised.
122
+
123
+ ### Captcha recovery mode `user_input`
124
+
125
+ ```python
126
+ cookidoo = Cookidoo(<your headful browser setup>)
127
+ await cookidoo.login(captcha_recovery_mode="user_input")
128
+ ```
129
+
130
+ _Be aware, using this option with a headless browser will indefinitely block the process in login, as it is waiting for user action._
131
+
132
+ ### Captcha recovery mode `capsolver`
133
+
134
+ This requires the `capsolver` to be installed.
135
+
136
+ ```bash
137
+ pip install capsolver
138
+ ```
139
+
140
+ ```python
141
+ cookidoo = Cookidoo(<your browser setup>)
142
+ await cookidoo.login(captcha_recovery_mode="capsolver")
143
+ ```
144
+
145
+ **This is not yet implemented.**
146
+
147
+ Alternatively, they also provide a [browser extension](https://docs.capsolver.com/en/guide/extension/introductions/), which might be a cleaner way.
148
+
149
+ ## Dev
150
+
151
+ Setup the dev environment using VSCode, it is highly recommended.
152
+
153
+ ```bash
154
+ python -m venv .venv
155
+ source .venv/bin/activate
156
+ pip install -r requirements_dev.txt
157
+ ```
158
+
159
+ Install [pre-commit](https://pre-commit.com)
160
+
161
+ ```bash
162
+ pre-commit install
163
+
164
+ # Run the commit hooks manually
165
+ pre-commit run --all-files
166
+ ```
167
+
168
+ Following VSCode integrations may be helpful:
169
+
170
+ - [ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)
171
+ - [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy)
172
+ - [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
173
+
174
+ # CHANGELOG
175
+
176
+ ## 0.1.0
177
+
178
+ Initial commit.
@@ -0,0 +1,148 @@
1
+ # Cookidoo API
2
+
3
+ [![PyPI version](https://badge.fury.io/py/cookidoo-api.svg)](https://pypi.org/p/cookidoo-api)
4
+
5
+ An unofficial python package to access Cookidoo.
6
+
7
+ [![Unit tests](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml)
8
+ [![Smoke test](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml)
9
+ [![Ruff](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml)
10
+ [![Mypy](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml)
11
+ [![Markdownlint](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml/badge.svg)](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml)
12
+
13
+ [![GitHub](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/miaucl)
14
+ [![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://patreon.com/miaucl)
15
+ [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://buymeacoffee.com/miaucl)
16
+ [![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.me/sponsormiaucl)
17
+
18
+ ## Disclaimer
19
+
20
+ The developers of this module are in no way endorsed by or affiliated with Cookidoo or Vorwerk, or any associated subsidiaries, logos or trademarks.
21
+
22
+ ## Installation
23
+
24
+ **Disclaimer: This library needs a runner (browser) to execute the calls through web automation. Make sure to have it correctly set up using one of the following options before proceeding.**
25
+
26
+ [Setup runner](https://github.com/cookidoo-api/blob/master/runners)
27
+
28
+ Once you have tested your runner, install the cookidoo library and use it with your preferred browser.
29
+
30
+ `pip install cookidoo-api`
31
+
32
+ ## Documentation
33
+
34
+ See below for usage examples. See [Exceptions](#exceptions) for API-specific exceptions and mitigation strategies for common exceptions.
35
+
36
+ ## Usage Example
37
+
38
+ The API is based on the async implementation of the library [`playwright`](https://playwright.dev/python/docs/api/class-playwright) in collaboration with a runner for browser emulation.
39
+
40
+ Make sure to have stored your credentials in the top-level file `.env` as such, to loaded by `dotenv`. Alternatively, provide the environment variables by any other `dotenv` compatible means.
41
+
42
+ ```text
43
+ EMAIL=your@mail.com
44
+ PASSWORD=password
45
+ ```
46
+
47
+ Run the [example script](https://github.com/miaucl/cookidoo-api/blob/master/example.py) and have a look at the inline comments for more explanation.
48
+
49
+ ## Exceptions
50
+
51
+ In case something goes wrong during a request, several [exceptions](https://github.com/miaucl/cookidoo/blob/master/cookidoo_api/exceptions.py) can be thrown.
52
+ They will either be
53
+
54
+ - `CookidooActionException`
55
+ - `CookidooAuthBotDetectionException`
56
+ - `CookidooAuthException`
57
+ - `CookidooConfigException`
58
+ - `CookidooNavigationException`
59
+ - `CookidooSelectorException`
60
+ - `CookidooUnavailableException`
61
+ - `CookidooUnexpectedStateException`
62
+
63
+ depending on the context. All inherit from `CookidooException`.
64
+
65
+ ### Another asyncio event loop is
66
+
67
+ With the async calls, you might encounter an error that another asyncio event loop is already running on the same thread. This is expected behavior according to the asyncio.run() [documentation](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). You cannot use more than one aiohttp session per thread, reuse the existing one!
68
+
69
+ ### Exception ignored: RuntimeError: Event loop is closed
70
+
71
+ Due to a known issue in some versions of aiohttp when using Windows, you might encounter a similar error to this:
72
+
73
+ ```python
74
+ Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000000>
75
+ Traceback (most recent call last):
76
+ File "C:\...\py38\lib\asyncio\proactor_events.py", line 116, in __del__
77
+ self.close()
78
+ File "C:\...\py38\lib\asyncio\proactor_events.py", line 108, in close
79
+ self._loop.call_soon(self._call_connection_lost, None)
80
+ File "C:\...\py38\lib\asyncio\base_events.py", line 719, in call_soon
81
+ self._check_closed()
82
+ File "C:\...\py38\lib\asyncio\base_events.py", line 508, in _check_closed
83
+ raise RuntimeError('Event loop is closed')
84
+ RuntimeError: Event loop is closed
85
+ ```
86
+
87
+ You can fix this according to [this](https://stackoverflow.com/questions/68123296/asyncio-throws-runtime-error-with-exception-ignored) StackOverflow answer by adding the following line of code before executing the library:
88
+
89
+ ```python
90
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
91
+ ```
92
+
93
+ ## Bot detection and captcha problems
94
+
95
+ There is an inbuilt bot detection on cookidoo which can block the login process. There is a clear error message, when that happens. The tokens are valid for a fixed duration and therefore the library tries to minimize the amount of logins required to avoid the captcha process. Unfortunately, this is not always possible when developing or debugging a setup, and you might run into it. To continue, either wait a day or switch to a runner with a gui and enable `captcha` mode to manually solve the captcha during the login or a service such as [`capsolver`](https://www.capsolver.com/).
96
+
97
+ It is generally advised, to first try the login in `fail` mode and only activate a recovery mode on a `CookidooAuthBotDetectionException` raised.
98
+
99
+ ### Captcha recovery mode `user_input`
100
+
101
+ ```python
102
+ cookidoo = Cookidoo(<your headful browser setup>)
103
+ await cookidoo.login(captcha_recovery_mode="user_input")
104
+ ```
105
+
106
+ _Be aware, using this option with a headless browser will indefinitely block the process in login, as it is waiting for user action._
107
+
108
+ ### Captcha recovery mode `capsolver`
109
+
110
+ This requires the `capsolver` to be installed.
111
+
112
+ ```bash
113
+ pip install capsolver
114
+ ```
115
+
116
+ ```python
117
+ cookidoo = Cookidoo(<your browser setup>)
118
+ await cookidoo.login(captcha_recovery_mode="capsolver")
119
+ ```
120
+
121
+ **This is not yet implemented.**
122
+
123
+ Alternatively, they also provide a [browser extension](https://docs.capsolver.com/en/guide/extension/introductions/), which might be a cleaner way.
124
+
125
+ ## Dev
126
+
127
+ Setup the dev environment using VSCode, it is highly recommended.
128
+
129
+ ```bash
130
+ python -m venv .venv
131
+ source .venv/bin/activate
132
+ pip install -r requirements_dev.txt
133
+ ```
134
+
135
+ Install [pre-commit](https://pre-commit.com)
136
+
137
+ ```bash
138
+ pre-commit install
139
+
140
+ # Run the commit hooks manually
141
+ pre-commit run --all-files
142
+ ```
143
+
144
+ Following VSCode integrations may be helpful:
145
+
146
+ - [ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)
147
+ - [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy)
148
+ - [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
@@ -0,0 +1,51 @@
1
+ """Cookidoo API package."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from .const import (
6
+ DEFAULT_COOKIDOO_CONFIG,
7
+ DEFAULT_NETWORK_TIMEOUT,
8
+ DEFAULT_RETRIES,
9
+ DEFAULT_TIMEOUT,
10
+ )
11
+ from .cookidoo import Cookidoo
12
+ from .exceptions import (
13
+ CookidooActionException,
14
+ CookidooAuthBotDetectionException,
15
+ CookidooAuthException,
16
+ CookidooConfigException,
17
+ CookidooException,
18
+ CookidooNavigationException,
19
+ CookidooSelectorException,
20
+ CookidooUnavailableException,
21
+ CookidooUnexpectedStateException,
22
+ )
23
+ from .types import (
24
+ CookidooBrowserType,
25
+ CookidooCaptchaRecoveryType,
26
+ CookidooConfig,
27
+ CookidooItem,
28
+ CookidooItemStateType,
29
+ )
30
+
31
+ __all__ = [
32
+ "Cookidoo",
33
+ "CookidooBrowserType",
34
+ "CookidooCaptchaRecoveryType",
35
+ "CookidooItemStateType",
36
+ "CookidooConfig",
37
+ "CookidooItem",
38
+ "CookidooException",
39
+ "CookidooConfigException",
40
+ "CookidooAuthException",
41
+ "CookidooAuthBotDetectionException",
42
+ "CookidooSelectorException",
43
+ "CookidooActionException",
44
+ "CookidooUnavailableException",
45
+ "CookidooUnexpectedStateException",
46
+ "CookidooNavigationException",
47
+ "DEFAULT_COOKIDOO_CONFIG",
48
+ "DEFAULT_RETRIES",
49
+ "DEFAULT_NETWORK_TIMEOUT",
50
+ "DEFAULT_TIMEOUT",
51
+ ]
@@ -0,0 +1,107 @@
1
+ """Constants for Cookidoo API."""
2
+
3
+ from typing import Final
4
+
5
+ from cookidoo_api.types import CookidooConfig
6
+
7
+ LOGIN_START_URL: Final = "https://cookidoo.ch"
8
+ LOGIN_START_SELECTOR: Final = "#layout--default > header > div > core-nav > nav > div.core-nav__container > ul.core-nav__links.unauthenticated-only > li:nth-child(2) > a"
9
+ LOGIN_EMAIL_SELECTOR: Final = "#email"
10
+ LOGIN_PASSWORD_SELECTOR: Final = "#password"
11
+ LOGIN_SUBMIT_SELECTOR: Final = 'button[type="submit"]'
12
+ LOGIN_CAPTCHA_SELECTOR: Final = "#amzn-captcha-verify-button"
13
+ LOGIN_ERROR_NOTIFICATION_SELECTOR: Final = ".notification__unobtrusive-error"
14
+ COOKIE_VALIDATION_URL: Final = "https://cookidoo.ch/profile/account"
15
+ COOKIE_VALIDATION_SELECTOR: Final = (
16
+ "main > section > .profile-indent > .profile-main-headline"
17
+ )
18
+ SHOPPING_LIST_URL: Final = "https://cookidoo.ch/shopping"
19
+ SHOPPING_LIST_SELECTOR: Final = "pm-shopping-list"
20
+
21
+ SHOPPING_LIST_EMPTY_SELECTOR: Final = "core-error-page"
22
+
23
+ SHOPPING_LIST_OPTIONS_SELECTOR: Final = "#shopping-list-options"
24
+ SHOPPING_LIST_CLEAR_ALL_OPTION_SELECTOR: Final = "#clearAllRecipes"
25
+ SHOPPING_LIST_CLEAR_ALL_MODAL_CONFIRM_SELECTOR: Final = (
26
+ 'core-modal [data-action="clear-all"] button[type="submit"]'
27
+ )
28
+
29
+ SHOPPING_LIST_ITEMS_SELECTOR: Final = "pm-ingredients-list #byCategory"
30
+ SHOPPING_LIST_CHECKED_ITEMS_SELECTOR: Final = "pm-checked-list-wrapper"
31
+
32
+ SHOPPING_LIST_ITEM_SUB_SELECTOR: Final = "li:not(.additional-items-list-item)"
33
+ SHOPPING_LIST_ITEM_LABEL_SUB_SELECTOR: Final = (
34
+ 'label span[data-type="ingredientNotation"]'
35
+ )
36
+ SHOPPING_LIST_ITEM_QUANTITY_SUB_SELECTOR: Final = 'label span[data-type="value"]'
37
+ SHOPPING_LIST_ITEM_UNIT_SUB_SELECTOR: Final = 'label span[data-type="unitNotation"]'
38
+ SHOPPING_LIST_ITEM_ID_SUB_SELECTOR: Final = "input[data-value]"
39
+ SHOPPING_LIST_ITEM_ID_ATTR: Final = "data-value"
40
+ SHOPPING_LIST_CHECKBOX_SUB_SELECTOR: Final = "core-checkbox"
41
+
42
+ SHOPPING_LIST_ADDITIONAL_ITEMS_SELECTOR: Final = "pm-additional-items-list"
43
+ SHOPPING_LIST_ADDITIONAL_CHECKED_ITEMS_SELECTOR: Final = "pm-checked-list-wrapper"
44
+ SHOPPING_LIST_ADDITIONAL_ITEM_SUB_SELECTOR: Final = "li.additional-items-list-item"
45
+ SHOPPING_LIST_ADDITIONAL_ITEM_HOVER_SUB_SELECTOR: Final = "> div"
46
+ SHOPPING_LIST_ADDITIONAL_ITEM_LABEL_SUB_SELECTOR: Final = (
47
+ 'label span[data-type="name"], label span[data-type="value"]'
48
+ )
49
+ SHOPPING_LIST_ADDITIONAL_ITEM_ID_SUB_SELECTOR: Final = "input[data-value]"
50
+ SHOPPING_LIST_ADDITIONAL_ITEM_ID_ATTR: Final = "data-value"
51
+ SHOPPING_LIST_ADDITIONAL_CHECKBOX_SUB_SELECTOR: Final = "core-checkbox"
52
+ SHOPPING_LIST_ADDITIONAL_ITEM_DELETE_SUB_SELECTOR: Final = 'span[data-type="delete"]'
53
+ SHOPPING_LIST_ADDITIONAL_ITEM_EDIT_SUB_SELECTOR: Final = 'span[data-type="edit"]'
54
+
55
+ SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_SELECTOR: Final = "pm-edit-additional-item"
56
+ SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_INPUT_SUB_SELECTOR: Final = 'input[type="text"]'
57
+ SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_CONFIRM_SUB_SELECTOR: Final = (
58
+ 'button:not([type="button"])'
59
+ )
60
+
61
+ SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_SELECTOR: Final = "pm-add-additional-item"
62
+ SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_INPUT_SUB_SELECTOR: Final = "input"
63
+ SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_CONFIRM_SUB_SELECTOR: Final = "button"
64
+
65
+ SHOPPING_LIST_ITEMS_TAB_SELECTOR: Final = "core-content-navigation button:nth-child(1)"
66
+ SHOPPING_LIST_RECIPES_TAB_SELECTOR: Final = (
67
+ "core-content-navigation button:nth-child(2)"
68
+ )
69
+ SHOPPING_LIST_RECIPE_OPTIONS_SELECTOR_TEMPLATE: Final = (
70
+ '[id="shopping-list-trigger-{}"]'
71
+ )
72
+ SHOPPING_LIST_RECIPE_REMOVE_OPTION_SELECTOR_TEMPLATE: Final = 'core-context-menu[trigger-id="shopping-list-trigger-{}"] core-handle-form[data-action="remove-recipes"]'
73
+
74
+ RECIPE_URL_PREFIX: Final = "https://cookidoo.ch/recipes/recipe/"
75
+ RECIPE_COOK_TODAY_SELECTOR: Final = '[id="cook-today-handle-form"] button'
76
+ RECIPE_ADD_OPTIONS_SELECTOR_TEMPLATE: Final = '[id="add-trigger-{}"]'
77
+ RECIPE_ADD_OPTION_SHOPPING_LIST_SELECTOR: Final = (
78
+ '[id="add-to-shopping-list-button"] button'
79
+ )
80
+ RECIPE_ADD_TO_SHOPPING_LIST_CONFIRM_SELECTOR: Final = (
81
+ 'core-conversion-teaser [href^="/shopping"]'
82
+ )
83
+ DOM_CHECK_ATTACHED: Final = "element => document.body.contains(element)"
84
+
85
+ DEFAULT_RETRIES = 3
86
+ DEFAULT_NETWORK_TIMEOUT = 5000
87
+ DEFAULT_TIMEOUT = 3000
88
+
89
+
90
+ DEFAULT_COOKIDOO_CONFIG = CookidooConfig(
91
+ {
92
+ "language_code": "de-CH",
93
+ "browser": "firefox",
94
+ "remote_addr": None,
95
+ "remote_port": "9222",
96
+ "headless": True,
97
+ "email": "your@email",
98
+ "password": "1234password!",
99
+ "network_timeout": DEFAULT_NETWORK_TIMEOUT,
100
+ "timeout": DEFAULT_TIMEOUT,
101
+ "retries": DEFAULT_RETRIES,
102
+ "load_media": True,
103
+ "tracing": False,
104
+ "screenshots": False,
105
+ "out_dir": "./out",
106
+ }
107
+ )