click-extended 0.4.0__tar.gz → 1.0.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.
Files changed (28) hide show
  1. {click_extended-0.4.0/click_extended.egg-info → click_extended-1.0.0}/PKG-INFO +99 -29
  2. {click_extended-0.4.0 → click_extended-1.0.0}/README.md +92 -28
  3. click_extended-1.0.0/click_extended/__init__.py +21 -0
  4. click_extended-1.0.0/click_extended/classes.py +25 -0
  5. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended/types.py +1 -1
  6. {click_extended-0.4.0 → click_extended-1.0.0/click_extended.egg-info}/PKG-INFO +99 -29
  7. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended.egg-info/SOURCES.txt +1 -11
  8. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended.egg-info/requires.txt +8 -0
  9. {click_extended-0.4.0 → click_extended-1.0.0}/pyproject.toml +9 -2
  10. {click_extended-0.4.0 → click_extended-1.0.0}/tests/test_lifecycle.py +7 -10
  11. click_extended-0.4.0/click_extended/__init__.py +0 -17
  12. click_extended-0.4.0/click_extended/classes.py +0 -21
  13. click_extended-0.4.0/tests/test_argument_node.py +0 -1059
  14. click_extended-0.4.0/tests/test_child_node.py +0 -2633
  15. click_extended-0.4.0/tests/test_context.py +0 -867
  16. click_extended-0.4.0/tests/test_errors.py +0 -478
  17. click_extended-0.4.0/tests/test_node.py +0 -112
  18. click_extended-0.4.0/tests/test_option_node.py +0 -1346
  19. click_extended-0.4.0/tests/test_parent_node.py +0 -947
  20. click_extended-0.4.0/tests/test_root_node.py +0 -2240
  21. click_extended-0.4.0/tests/test_tag.py +0 -766
  22. click_extended-0.4.0/tests/test_tree.py +0 -1481
  23. {click_extended-0.4.0 → click_extended-1.0.0}/AUTHORS.md +0 -0
  24. {click_extended-0.4.0 → click_extended-1.0.0}/LICENSE +0 -0
  25. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended/errors.py +0 -0
  26. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended.egg-info/dependency_links.txt +0 -0
  27. {click_extended-0.4.0 → click_extended-1.0.0}/click_extended.egg-info/top_level.txt +0 -0
  28. {click_extended-0.4.0 → click_extended-1.0.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: click_extended
3
- Version: 0.4.0
3
+ Version: 1.0.0
4
4
  Summary: An extension to Click with additional features like automatic async support, aliasing and a modular decorator system.
5
5
  Author-email: Marcus Fredriksson <marcus@marcusfredriksson.com>
6
6
  License: MIT License
@@ -47,6 +47,10 @@ License-File: LICENSE
47
47
  License-File: AUTHORS.md
48
48
  Requires-Dist: click>=8.3.0
49
49
  Requires-Dist: python-dotenv>=1.2.1
50
+ Requires-Dist: pyyaml>=6.0.3
51
+ Requires-Dist: email-validator>=2.3.0
52
+ Requires-Dist: python-slugify>=8.0.4
53
+ Requires-Dist: tomli>=2.0.0; python_version < "3.11"
50
54
  Provides-Extra: build
51
55
  Requires-Dist: build; extra == "build"
52
56
  Requires-Dist: twine; extra == "build"
@@ -59,6 +63,8 @@ Requires-Dist: pylint>=3.0.0; extra == "dev"
59
63
  Requires-Dist: isort>=5.12.0; extra == "dev"
60
64
  Requires-Dist: black>=25.9.0; extra == "dev"
61
65
  Requires-Dist: pre-commit>=4.3.0; extra == "dev"
66
+ Requires-Dist: types-PyYAML>=6.0.12.20250915; extra == "dev"
67
+ Requires-Dist: tomli>=2.0.0; extra == "dev"
62
68
  Dynamic: license-file
63
69
 
64
70
  ![Banner](./assets/click-extended-banner.png)
@@ -88,6 +94,7 @@ An extension of the [Click](https://github.com/pallets/click) library with addit
88
94
  - **Environment Variables**: Built-in support for loading and using environment variables as a data source.
89
95
  - **Full Type Support**: Built with type-hinting from the ground up, meaning everything is fully typed.
90
96
  - **Improved Errors**: Improved error output like tips, debugging, and more.
97
+ - **Short Flag Concatenation**: Automatically support concatenating short hand flags where `-r -f` is the same as `-rf`.
91
98
 
92
99
  ## Installation
93
100
 
@@ -116,14 +123,18 @@ def my_function(value: str, count: int):
116
123
 
117
124
  if __name__ == "__main__":
118
125
  my_function()
126
+ ```
119
127
 
120
- # $ python cli.py "Hello world"
121
- # Hello world
128
+ ```bash
129
+ $ python cli.py "Hello world"
130
+ Hello world
131
+ ```
122
132
 
123
- # $ python cli.py "Hello world" --count 3
124
- # Hello world
125
- # Hello world
126
- # Hello world
133
+ ```bash
134
+ $ python cli.py "Hello world" --count 3
135
+ Hello world
136
+ Hello world
137
+ Hello world
127
138
  ```
128
139
 
129
140
  ### Basic Command Line Interface
@@ -146,16 +157,20 @@ def my_function(value: str, count: int):
146
157
 
147
158
  if __name__ == "__main__":
148
159
  my_group()
160
+ ```
149
161
 
150
- # $ python cli.py my_function "Hello world"
151
- # Running initialization code...
152
- # Hello world
162
+ ```bash
163
+ $ python cli.py my_function "Hello world"
164
+ Running initialization code...
165
+ Hello world
166
+ ```
153
167
 
154
- # $ python cli.py my_function "Hello world" --count 3
155
- # Running initialization code...
156
- # Hello world
157
- # Hello world
158
- # Hello world
168
+ ```bash
169
+ $ python cli.py my_function "Hello world" --count 3
170
+ Running initialization code...
171
+ Hello world
172
+ Hello world
173
+ Hello world
159
174
  ```
160
175
 
161
176
  ### Using Environment Variables
@@ -181,21 +196,72 @@ def my_function_2(api_key: str):
181
196
 
182
197
  if __name__ == "__main__":
183
198
  my_group()
199
+ ```
200
+
201
+ ```bash
202
+ $ python cli.py my_function_1
203
+ The API key is: None
204
+ ```
205
+
206
+ ```bash
207
+ $ API_KEY=api-key python cli.py my_function_1
208
+ The API key is: api-key
209
+ ```
210
+
211
+ ```bash
212
+ $ python cli.py my_function_2
213
+ ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
214
+ ```
215
+
216
+ ```bash
217
+ $ API_KEY=api-key python cli.py my_function_2
218
+ The API key is: api-key
219
+ ```
220
+
221
+ ### Load CSV Data
222
+
223
+ ```python
224
+ import pandas as pd
225
+ from click_extended import command, argument
226
+ from click_extended.decorators import to_path, load_csv
227
+
228
+ @command()
229
+ @argument("file", param="data")
230
+ @to_path(extensions=["csv"], exists=True)
231
+ @load_csv()
232
+ def my_command(data: dict[str, Any], *args: Any, **kwargs: Any) -> None:
233
+ df = pd.DataFrame(data)
234
+ print(df.head())
235
+ ```
184
236
 
185
- # $ python cli.py my_function_1
186
- # The API key is: None
237
+ _Note: `pandas` is not installed in this library and must be installed manually due to size._
187
238
 
188
- # $ API_KEY=api-key python cli.py my_function_1
189
- # The API key is: api-key
239
+ ### Pre-Built Children
190
240
 
191
- # $ python cli.py my_function_2
192
- # ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
241
+ This library includes a vast number of pre-built children, everything from checking values to transforming values.
193
242
 
194
- # $ API_KEY=api-key python cli.py my_function_2
195
- # The API key is: api-key
243
+ ```python
244
+ from click_extended import command, argument, option
245
+ from click_extended.decorators import to_snake_case, strip, is_email, minimum, dependencies
246
+
247
+ @command()
248
+ @dependencies("username", "email", "password")
249
+ @argument("username")
250
+ @to_snake_case()
251
+ @strip()
252
+ @option("email")
253
+ @is_email()
254
+ @option("password")
255
+ @minimum(8)
256
+ def create_account(username: str, email: str, password: str) -> None:
257
+ print("Username:", username)
258
+ print("Email:", email)
259
+ print("Password:", password)
196
260
  ```
197
261
 
198
- ### Custom Children
262
+ ### Custom Nodes
263
+
264
+ If the library does not include a decorator you need, you can easily create your own. Read more about creating your own [children](./docs/core/CHILD_NODE.md), [validators](./docs/core/VALIDATION_NODE.md), [child validators](./docs/core/CHILD_VALIDATION_NODE.md) or [parents](./docs/core/PARENT_NODE.md).
199
265
 
200
266
  ```python
201
267
  from typing import Any
@@ -205,7 +271,7 @@ from click_extended.classes import ChildNode
205
271
  from click_extended.types import Context, Decorator
206
272
 
207
273
  class MyCustomChild(ChildNode):
208
- def handle_primitive(
274
+ def handle_string(
209
275
  self,
210
276
  value: str,
211
277
  context: Context,
@@ -236,12 +302,16 @@ def my_function(value: str):
236
302
 
237
303
  if __name__ == "__main__":
238
304
  my_group()
305
+ ```
239
306
 
240
- # $ python cli.py my_function valid
241
- # The value 'VALID' should be uppercase.
307
+ ```bash
308
+ $ python cli.py my_function valid
309
+ The value 'VALID' should be uppercase.
310
+ ```
242
311
 
243
- # $ python cli.py my_function invalid
244
- # ValueError (my_function): "The value 'invalid' is not valid"
312
+ ```bash
313
+ $ python cli.py my_function invalid
314
+ ValueError (my_function): "The value 'invalid' is not valid"
245
315
  ```
246
316
 
247
317
  ## Documentation
@@ -25,6 +25,7 @@ An extension of the [Click](https://github.com/pallets/click) library with addit
25
25
  - **Environment Variables**: Built-in support for loading and using environment variables as a data source.
26
26
  - **Full Type Support**: Built with type-hinting from the ground up, meaning everything is fully typed.
27
27
  - **Improved Errors**: Improved error output like tips, debugging, and more.
28
+ - **Short Flag Concatenation**: Automatically support concatenating short hand flags where `-r -f` is the same as `-rf`.
28
29
 
29
30
  ## Installation
30
31
 
@@ -53,14 +54,18 @@ def my_function(value: str, count: int):
53
54
 
54
55
  if __name__ == "__main__":
55
56
  my_function()
57
+ ```
56
58
 
57
- # $ python cli.py "Hello world"
58
- # Hello world
59
+ ```bash
60
+ $ python cli.py "Hello world"
61
+ Hello world
62
+ ```
59
63
 
60
- # $ python cli.py "Hello world" --count 3
61
- # Hello world
62
- # Hello world
63
- # Hello world
64
+ ```bash
65
+ $ python cli.py "Hello world" --count 3
66
+ Hello world
67
+ Hello world
68
+ Hello world
64
69
  ```
65
70
 
66
71
  ### Basic Command Line Interface
@@ -83,16 +88,20 @@ def my_function(value: str, count: int):
83
88
 
84
89
  if __name__ == "__main__":
85
90
  my_group()
91
+ ```
86
92
 
87
- # $ python cli.py my_function "Hello world"
88
- # Running initialization code...
89
- # Hello world
93
+ ```bash
94
+ $ python cli.py my_function "Hello world"
95
+ Running initialization code...
96
+ Hello world
97
+ ```
90
98
 
91
- # $ python cli.py my_function "Hello world" --count 3
92
- # Running initialization code...
93
- # Hello world
94
- # Hello world
95
- # Hello world
99
+ ```bash
100
+ $ python cli.py my_function "Hello world" --count 3
101
+ Running initialization code...
102
+ Hello world
103
+ Hello world
104
+ Hello world
96
105
  ```
97
106
 
98
107
  ### Using Environment Variables
@@ -118,21 +127,72 @@ def my_function_2(api_key: str):
118
127
 
119
128
  if __name__ == "__main__":
120
129
  my_group()
130
+ ```
131
+
132
+ ```bash
133
+ $ python cli.py my_function_1
134
+ The API key is: None
135
+ ```
136
+
137
+ ```bash
138
+ $ API_KEY=api-key python cli.py my_function_1
139
+ The API key is: api-key
140
+ ```
141
+
142
+ ```bash
143
+ $ python cli.py my_function_2
144
+ ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
145
+ ```
146
+
147
+ ```bash
148
+ $ API_KEY=api-key python cli.py my_function_2
149
+ The API key is: api-key
150
+ ```
151
+
152
+ ### Load CSV Data
153
+
154
+ ```python
155
+ import pandas as pd
156
+ from click_extended import command, argument
157
+ from click_extended.decorators import to_path, load_csv
158
+
159
+ @command()
160
+ @argument("file", param="data")
161
+ @to_path(extensions=["csv"], exists=True)
162
+ @load_csv()
163
+ def my_command(data: dict[str, Any], *args: Any, **kwargs: Any) -> None:
164
+ df = pd.DataFrame(data)
165
+ print(df.head())
166
+ ```
121
167
 
122
- # $ python cli.py my_function_1
123
- # The API key is: None
168
+ _Note: `pandas` is not installed in this library and must be installed manually due to size._
124
169
 
125
- # $ API_KEY=api-key python cli.py my_function_1
126
- # The API key is: api-key
170
+ ### Pre-Built Children
127
171
 
128
- # $ python cli.py my_function_2
129
- # ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
172
+ This library includes a vast number of pre-built children, everything from checking values to transforming values.
130
173
 
131
- # $ API_KEY=api-key python cli.py my_function_2
132
- # The API key is: api-key
174
+ ```python
175
+ from click_extended import command, argument, option
176
+ from click_extended.decorators import to_snake_case, strip, is_email, minimum, dependencies
177
+
178
+ @command()
179
+ @dependencies("username", "email", "password")
180
+ @argument("username")
181
+ @to_snake_case()
182
+ @strip()
183
+ @option("email")
184
+ @is_email()
185
+ @option("password")
186
+ @minimum(8)
187
+ def create_account(username: str, email: str, password: str) -> None:
188
+ print("Username:", username)
189
+ print("Email:", email)
190
+ print("Password:", password)
133
191
  ```
134
192
 
135
- ### Custom Children
193
+ ### Custom Nodes
194
+
195
+ If the library does not include a decorator you need, you can easily create your own. Read more about creating your own [children](./docs/core/CHILD_NODE.md), [validators](./docs/core/VALIDATION_NODE.md), [child validators](./docs/core/CHILD_VALIDATION_NODE.md) or [parents](./docs/core/PARENT_NODE.md).
136
196
 
137
197
  ```python
138
198
  from typing import Any
@@ -142,7 +202,7 @@ from click_extended.classes import ChildNode
142
202
  from click_extended.types import Context, Decorator
143
203
 
144
204
  class MyCustomChild(ChildNode):
145
- def handle_primitive(
205
+ def handle_string(
146
206
  self,
147
207
  value: str,
148
208
  context: Context,
@@ -173,12 +233,16 @@ def my_function(value: str):
173
233
 
174
234
  if __name__ == "__main__":
175
235
  my_group()
236
+ ```
176
237
 
177
- # $ python cli.py my_function valid
178
- # The value 'VALID' should be uppercase.
238
+ ```bash
239
+ $ python cli.py my_function valid
240
+ The value 'VALID' should be uppercase.
241
+ ```
179
242
 
180
- # $ python cli.py my_function invalid
181
- # ValueError (my_function): "The value 'invalid' is not valid"
243
+ ```bash
244
+ $ python cli.py my_function invalid
245
+ ValueError (my_function): "The value 'invalid' is not valid"
182
246
  ```
183
247
 
184
248
  ## Documentation
@@ -0,0 +1,21 @@
1
+ """Initialization file for the 'click_extended' module."""
2
+
3
+ from click_extended.core.decorators.argument import argument
4
+ from click_extended.core.decorators.command import command
5
+ from click_extended.core.decorators.env import env
6
+ from click_extended.core.decorators.group import group
7
+ from click_extended.core.decorators.option import option
8
+ from click_extended.core.decorators.prompt import prompt
9
+ from click_extended.core.decorators.selection import selection
10
+ from click_extended.core.decorators.tag import tag
11
+
12
+ __all__ = [
13
+ "argument",
14
+ "command",
15
+ "env",
16
+ "group",
17
+ "option",
18
+ "prompt",
19
+ "selection",
20
+ "tag",
21
+ ]
@@ -0,0 +1,25 @@
1
+ """Classes used in `click_extended`."""
2
+
3
+ from click_extended.core.decorators.command import Command
4
+ from click_extended.core.decorators.group import Group
5
+ from click_extended.core.decorators.tag import Tag
6
+ from click_extended.core.nodes.argument_node import ArgumentNode
7
+ from click_extended.core.nodes.child_node import ChildNode
8
+ from click_extended.core.nodes.child_validation_node import ChildValidationNode
9
+ from click_extended.core.nodes.node import Node
10
+ from click_extended.core.nodes.option_node import OptionNode
11
+ from click_extended.core.nodes.parent_node import ParentNode
12
+ from click_extended.core.nodes.validation_node import ValidationNode
13
+
14
+ __all__ = [
15
+ "Node",
16
+ "ChildNode",
17
+ "ChildValidationNode",
18
+ "ParentNode",
19
+ "ArgumentNode",
20
+ "OptionNode",
21
+ "Command",
22
+ "Group",
23
+ "Tag",
24
+ "ValidationNode",
25
+ ]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any, Callable
4
4
 
5
- from click_extended.core.context import Context
5
+ from click_extended.core.other.context import Context
6
6
 
7
7
  Decorator = Callable[[Callable[..., Any]], Callable[..., Any]]
8
8
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: click_extended
3
- Version: 0.4.0
3
+ Version: 1.0.0
4
4
  Summary: An extension to Click with additional features like automatic async support, aliasing and a modular decorator system.
5
5
  Author-email: Marcus Fredriksson <marcus@marcusfredriksson.com>
6
6
  License: MIT License
@@ -47,6 +47,10 @@ License-File: LICENSE
47
47
  License-File: AUTHORS.md
48
48
  Requires-Dist: click>=8.3.0
49
49
  Requires-Dist: python-dotenv>=1.2.1
50
+ Requires-Dist: pyyaml>=6.0.3
51
+ Requires-Dist: email-validator>=2.3.0
52
+ Requires-Dist: python-slugify>=8.0.4
53
+ Requires-Dist: tomli>=2.0.0; python_version < "3.11"
50
54
  Provides-Extra: build
51
55
  Requires-Dist: build; extra == "build"
52
56
  Requires-Dist: twine; extra == "build"
@@ -59,6 +63,8 @@ Requires-Dist: pylint>=3.0.0; extra == "dev"
59
63
  Requires-Dist: isort>=5.12.0; extra == "dev"
60
64
  Requires-Dist: black>=25.9.0; extra == "dev"
61
65
  Requires-Dist: pre-commit>=4.3.0; extra == "dev"
66
+ Requires-Dist: types-PyYAML>=6.0.12.20250915; extra == "dev"
67
+ Requires-Dist: tomli>=2.0.0; extra == "dev"
62
68
  Dynamic: license-file
63
69
 
64
70
  ![Banner](./assets/click-extended-banner.png)
@@ -88,6 +94,7 @@ An extension of the [Click](https://github.com/pallets/click) library with addit
88
94
  - **Environment Variables**: Built-in support for loading and using environment variables as a data source.
89
95
  - **Full Type Support**: Built with type-hinting from the ground up, meaning everything is fully typed.
90
96
  - **Improved Errors**: Improved error output like tips, debugging, and more.
97
+ - **Short Flag Concatenation**: Automatically support concatenating short hand flags where `-r -f` is the same as `-rf`.
91
98
 
92
99
  ## Installation
93
100
 
@@ -116,14 +123,18 @@ def my_function(value: str, count: int):
116
123
 
117
124
  if __name__ == "__main__":
118
125
  my_function()
126
+ ```
119
127
 
120
- # $ python cli.py "Hello world"
121
- # Hello world
128
+ ```bash
129
+ $ python cli.py "Hello world"
130
+ Hello world
131
+ ```
122
132
 
123
- # $ python cli.py "Hello world" --count 3
124
- # Hello world
125
- # Hello world
126
- # Hello world
133
+ ```bash
134
+ $ python cli.py "Hello world" --count 3
135
+ Hello world
136
+ Hello world
137
+ Hello world
127
138
  ```
128
139
 
129
140
  ### Basic Command Line Interface
@@ -146,16 +157,20 @@ def my_function(value: str, count: int):
146
157
 
147
158
  if __name__ == "__main__":
148
159
  my_group()
160
+ ```
149
161
 
150
- # $ python cli.py my_function "Hello world"
151
- # Running initialization code...
152
- # Hello world
162
+ ```bash
163
+ $ python cli.py my_function "Hello world"
164
+ Running initialization code...
165
+ Hello world
166
+ ```
153
167
 
154
- # $ python cli.py my_function "Hello world" --count 3
155
- # Running initialization code...
156
- # Hello world
157
- # Hello world
158
- # Hello world
168
+ ```bash
169
+ $ python cli.py my_function "Hello world" --count 3
170
+ Running initialization code...
171
+ Hello world
172
+ Hello world
173
+ Hello world
159
174
  ```
160
175
 
161
176
  ### Using Environment Variables
@@ -181,21 +196,72 @@ def my_function_2(api_key: str):
181
196
 
182
197
  if __name__ == "__main__":
183
198
  my_group()
199
+ ```
200
+
201
+ ```bash
202
+ $ python cli.py my_function_1
203
+ The API key is: None
204
+ ```
205
+
206
+ ```bash
207
+ $ API_KEY=api-key python cli.py my_function_1
208
+ The API key is: api-key
209
+ ```
210
+
211
+ ```bash
212
+ $ python cli.py my_function_2
213
+ ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
214
+ ```
215
+
216
+ ```bash
217
+ $ API_KEY=api-key python cli.py my_function_2
218
+ The API key is: api-key
219
+ ```
220
+
221
+ ### Load CSV Data
222
+
223
+ ```python
224
+ import pandas as pd
225
+ from click_extended import command, argument
226
+ from click_extended.decorators import to_path, load_csv
227
+
228
+ @command()
229
+ @argument("file", param="data")
230
+ @to_path(extensions=["csv"], exists=True)
231
+ @load_csv()
232
+ def my_command(data: dict[str, Any], *args: Any, **kwargs: Any) -> None:
233
+ df = pd.DataFrame(data)
234
+ print(df.head())
235
+ ```
184
236
 
185
- # $ python cli.py my_function_1
186
- # The API key is: None
237
+ _Note: `pandas` is not installed in this library and must be installed manually due to size._
187
238
 
188
- # $ API_KEY=api-key python cli.py my_function_1
189
- # The API key is: api-key
239
+ ### Pre-Built Children
190
240
 
191
- # $ python cli.py my_function_2
192
- # ProcessError (my_function_2): Required environment variable 'API_KEY' is not set.
241
+ This library includes a vast number of pre-built children, everything from checking values to transforming values.
193
242
 
194
- # $ API_KEY=api-key python cli.py my_function_2
195
- # The API key is: api-key
243
+ ```python
244
+ from click_extended import command, argument, option
245
+ from click_extended.decorators import to_snake_case, strip, is_email, minimum, dependencies
246
+
247
+ @command()
248
+ @dependencies("username", "email", "password")
249
+ @argument("username")
250
+ @to_snake_case()
251
+ @strip()
252
+ @option("email")
253
+ @is_email()
254
+ @option("password")
255
+ @minimum(8)
256
+ def create_account(username: str, email: str, password: str) -> None:
257
+ print("Username:", username)
258
+ print("Email:", email)
259
+ print("Password:", password)
196
260
  ```
197
261
 
198
- ### Custom Children
262
+ ### Custom Nodes
263
+
264
+ If the library does not include a decorator you need, you can easily create your own. Read more about creating your own [children](./docs/core/CHILD_NODE.md), [validators](./docs/core/VALIDATION_NODE.md), [child validators](./docs/core/CHILD_VALIDATION_NODE.md) or [parents](./docs/core/PARENT_NODE.md).
199
265
 
200
266
  ```python
201
267
  from typing import Any
@@ -205,7 +271,7 @@ from click_extended.classes import ChildNode
205
271
  from click_extended.types import Context, Decorator
206
272
 
207
273
  class MyCustomChild(ChildNode):
208
- def handle_primitive(
274
+ def handle_string(
209
275
  self,
210
276
  value: str,
211
277
  context: Context,
@@ -236,12 +302,16 @@ def my_function(value: str):
236
302
 
237
303
  if __name__ == "__main__":
238
304
  my_group()
305
+ ```
239
306
 
240
- # $ python cli.py my_function valid
241
- # The value 'VALID' should be uppercase.
307
+ ```bash
308
+ $ python cli.py my_function valid
309
+ The value 'VALID' should be uppercase.
310
+ ```
242
311
 
243
- # $ python cli.py my_function invalid
244
- # ValueError (my_function): "The value 'invalid' is not valid"
312
+ ```bash
313
+ $ python cli.py my_function invalid
314
+ ValueError (my_function): "The value 'invalid' is not valid"
245
315
  ```
246
316
 
247
317
  ## Documentation
@@ -11,14 +11,4 @@ click_extended.egg-info/SOURCES.txt
11
11
  click_extended.egg-info/dependency_links.txt
12
12
  click_extended.egg-info/requires.txt
13
13
  click_extended.egg-info/top_level.txt
14
- tests/test_argument_node.py
15
- tests/test_child_node.py
16
- tests/test_context.py
17
- tests/test_errors.py
18
- tests/test_lifecycle.py
19
- tests/test_node.py
20
- tests/test_option_node.py
21
- tests/test_parent_node.py
22
- tests/test_root_node.py
23
- tests/test_tag.py
24
- tests/test_tree.py
14
+ tests/test_lifecycle.py
@@ -1,5 +1,11 @@
1
1
  click>=8.3.0
2
2
  python-dotenv>=1.2.1
3
+ pyyaml>=6.0.3
4
+ email-validator>=2.3.0
5
+ python-slugify>=8.0.4
6
+
7
+ [:python_version < "3.11"]
8
+ tomli>=2.0.0
3
9
 
4
10
  [build]
5
11
  build
@@ -14,3 +20,5 @@ pylint>=3.0.0
14
20
  isort>=5.12.0
15
21
  black>=25.9.0
16
22
  pre-commit>=4.3.0
23
+ types-PyYAML>=6.0.12.20250915
24
+ tomli>=2.0.0