tiferet 1.0.0b0__tar.gz → 1.0.0b2__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 (62) hide show
  1. {tiferet-1.0.0b0/tiferet.egg-info → tiferet-1.0.0b2}/PKG-INFO +1 -1
  2. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/README.md +123 -63
  3. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/setup.py +1 -1
  4. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/feature.py +6 -4
  5. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/handlers/container.py +12 -9
  6. {tiferet-1.0.0b0 → tiferet-1.0.0b2/tiferet.egg-info}/PKG-INFO +1 -1
  7. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/LICENSE +0 -0
  8. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/setup.cfg +0 -0
  9. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/__init__.py +0 -0
  10. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/clients/__init__.py +0 -0
  11. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/clients/yaml.py +0 -0
  12. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/commands/__init__.py +0 -0
  13. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/commands/app.py +0 -0
  14. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/commands/core.py +0 -0
  15. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/commands/dependencies.py +0 -0
  16. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/commands/settings.py +0 -0
  17. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/configs/__init__.py +0 -0
  18. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/configs/error.py +0 -0
  19. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/configs/settings.py +0 -0
  20. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/__init__.py +0 -0
  21. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/app.py +0 -0
  22. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/cache.py +0 -0
  23. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/container.py +0 -0
  24. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contexts/error.py +0 -0
  25. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/__init__.py +0 -0
  26. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/app.py +0 -0
  27. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/cache.py +0 -0
  28. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/container.py +0 -0
  29. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/error.py +0 -0
  30. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/feature.py +0 -0
  31. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/contracts/settings.py +0 -0
  32. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/__init__.py +0 -0
  33. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/app.py +0 -0
  34. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/container.py +0 -0
  35. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/error.py +0 -0
  36. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/feature.py +0 -0
  37. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/data/settings.py +0 -0
  38. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/__init__.py +0 -0
  39. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/app.py +0 -0
  40. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/container.py +0 -0
  41. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/core.py +0 -0
  42. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/error.py +0 -0
  43. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/domain/feature.py +0 -0
  44. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/handlers/__init__.py +0 -0
  45. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/handlers/error.py +0 -0
  46. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/handlers/feature.py +0 -0
  47. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/__init__.py +0 -0
  48. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/app.py +0 -0
  49. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/container.py +0 -0
  50. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/error.py +0 -0
  51. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/feature.py +0 -0
  52. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/models/settings.py +0 -0
  53. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/__init__.py +0 -0
  54. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/yaml/__init__.py +0 -0
  55. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/yaml/app.py +0 -0
  56. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/yaml/container.py +0 -0
  57. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/yaml/error.py +0 -0
  58. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet/proxies/yaml/feature.py +0 -0
  59. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet.egg-info/SOURCES.txt +0 -0
  60. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet.egg-info/dependency_links.txt +0 -0
  61. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet.egg-info/requires.txt +0 -0
  62. {tiferet-1.0.0b0 → tiferet-1.0.0b2}/tiferet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tiferet
3
- Version: 1.0.0b0
3
+ Version: 1.0.0b2
4
4
  Summary: A multi-purpose application framework embodying beauty in form.
5
5
  Home-page: https://github.com/greatstrength/app
6
6
  Download-URL: https://github.com/greatstrength/app
@@ -39,7 +39,7 @@ python3.10 --version
39
39
  You should see Python 3.10.x if successful.
40
40
 
41
41
  ### Setting Up a Virtual Environment
42
- To keep your project dependencies organized, create a virtual environment named tiferet_app for your calculator application:
42
+ To keep your project dependencies organized, create a virtual environment named `tiferet_app` for your calculator application:
43
43
 
44
44
  #### Create the Environment
45
45
 
@@ -65,13 +65,13 @@ tiferet_app\Scripts\activate
65
65
  source tiferet_app/bin/activate
66
66
  ```
67
67
 
68
- Your terminal should display (tiferet_app), confirming the environment is active. You can now install Tiferet and other dependencies without affecting your system’s Python setup.
68
+ Your terminal should display `(tiferet_app)`, confirming the environment is active. You can now install Tiferet and other dependencies without affecting your system’s Python setup.
69
69
  Deactivate the Environment
70
70
  When finished, deactivate the environment with:
71
71
  deactivate
72
72
 
73
73
  ## Your First Calculator App
74
- With your tiferet_app virtual environment activated, you're ready to install Tiferet and start building your calculator application. Follow these steps to set up your project and begin crafting with Tiferet’s elegant approach.
74
+ With your `tiferet_app` virtual environment activated, you're ready to install Tiferet and start building your calculator application. Follow these steps to set up your project and begin crafting with Tiferet’s elegant approach.
75
75
 
76
76
  ### Installing Tiferet
77
77
  Install the Tiferet package using pip in your activated virtual environment:
@@ -90,6 +90,7 @@ Create a project directory structure to organize your calculator application:
90
90
  ```plaintext
91
91
  project_root/
92
92
  ├── basic_calc.py
93
+ ├── calc_cli.py
93
94
  └── app/
94
95
  ├── commands/
95
96
  │ ├── __init__.py
@@ -97,21 +98,21 @@ project_root/
97
98
  │ └── valid.py
98
99
  ├── configs/
99
100
  │ ├── __init__.py
100
- │ └── config.yaml
101
+ │ └── config.yml
101
102
  └── models/
102
103
  ├── __init__.py
103
104
  └── calc.py
104
105
  ```
105
106
 
106
- The app/models/ directory will house the calculator’s domain model, app/commands/ will contain command classes for operations and validations, and app/configs/ will store configuration files. The basic_calc.py script at the root will initialize and run the application. While the app directory name is customizable for package releases, we recommend retaining it for internal or proprietary projects to maintain simplicity and consistency.
107
+ The `app/models/` directory will house the calculator’s domain model, `app/commands/` will contain command classes for operations and validations, and `app/configs/` will store configuration files. The `basic_calc.py` script at the root will initialize and run the application. While the app directory name is customizable for package releases, we recommend retaining it for internal or proprietary projects to maintain simplicity and consistency. The `calc_cli.py` script is a versatile scriptable interface that integrates easily with shell scripts or external systems.
107
108
 
108
109
  ## Crafting the Calculator Application
109
110
  With Tiferet installed and your project structured, it’s time to bring your calculator application to life. We’ll start by defining the domain model, then create command classes for arithmetic and validation, configure the application’s behavior through container attributes, features, errors, and context, and finally initialize and demonstrate the app with a script. This sequence showcases Tiferet’s harmonious design, weaving together models, commands, and configurations with grace.
110
111
 
111
- ### Defining the Number Model in models/calc.py
112
- The calculator’s numerical values are represented by a Number value object, defined in app/models/calc.py. This model encapsulates a string-based numerical value, validated to ensure it represents an integer or float, and provides a method to format it as a number.
112
+ ### Defining the Number Model in `models/calc.py`
113
+ The calculator’s numerical values are represented by a `Number` value object, defined in `app/models/calc.py`. This model encapsulates a string-based numerical value, validated to ensure it represents an integer or float, and provides a method to format it as a number.
113
114
 
114
- Create app/models/calc.py with the following content:
115
+ Create `app/models/calc.py` with the following content:
115
116
 
116
117
  ```python
117
118
  from tiferet.models import *
@@ -147,24 +148,24 @@ class Number(ValueObject):
147
148
  return int(self.value)
148
149
  ```
149
150
 
150
- The Number class uses Tiferet’s ValueObject to ensure immutability, with a StringType attribute validated by a regex to accept integers and floats (e.g., "123", "-123.45", ".123"). The is_float method checks for decimal points, and format converts the string to an int or float, enabling arithmetic operations.
151
+ The Number class uses Tiferet’s ValueObject to ensure immutability, with a `StringType` attribute validated by a regex to accept integers and floats (e.g., `"123"`, `"-123.45"`, `".123"`). The is_float method checks for decimal points, and format converts the string to an int or float, enabling arithmetic operations.
151
152
 
152
153
  ### Defining Command Classes in commands/calc.py and commands/valid.py
153
- Next, we define command classes to perform arithmetic operations and input validation. Arithmetic commands (AddNumber, SubtractNumber, MultiplyNumber, DivideNumber, ExponentiateNumber) are in app/commands/calc.py, while the validation command (ValidateNumber) is in app/commands/valid.py. All inherit from Tiferet’s Command base class, using the static Command.handle method for execution.
154
+ Next, we define command classes to perform arithmetic operations and input validation. Arithmetic commands (`AddNumber`, `SubtractNumber`, `MultiplyNumber`, `DivideNumber`, `ExponentiateNumber`) are in `app/commands/calc.py`, while the validation command (`ValidateNumber`) is in `app/commands/valid.py`. All inherit from Tiferet’s Command base class, using the static `Command.handle` method for execution.
154
155
 
155
156
  #### Arithmetic Commands in commands/calc.py
156
- Create app/commands/calc.py with the following content:
157
+ Create `app/commands/calc.py` with the following content:
157
158
 
158
159
  ```python
159
- from ..commands import Command
160
- from ..models import ModelObject
160
+ from tiferet.commands import *
161
+
161
162
  from ..models.calc import Number
162
163
 
163
164
  class AddNumber(Command):
164
165
  '''
165
166
  A command to perform addition of two numbers.
166
167
  '''
167
- def execute(self, a: Number, b: Number) -> Number:
168
+ def execute(self, a: Number, b: Number, **kwargs) -> Number:
168
169
  '''
169
170
  Execute the addition command.
170
171
 
@@ -172,16 +173,23 @@ class AddNumber(Command):
172
173
  :type a: Number
173
174
  :param b: A Number object representing the second number.
174
175
  :type b: Number
176
+ :param kwargs: Additional keyword arguments.
177
+ :type kwargs: dict
175
178
  :return: A Number object representing the sum of a and b.
176
179
  :rtype: Number
177
180
  '''
178
- return ModelObject.new(Number, value=str(a.format() + b.format()))
181
+
182
+ # Add formatted values of a and b.
183
+ result = a.format() + b.format()
184
+
185
+ # Return a new Number object with the result.
186
+ return result
179
187
 
180
188
  class SubtractNumber(Command):
181
189
  '''
182
190
  A command to perform subtraction of two numbers.
183
191
  '''
184
- def execute(self, a: Number, b: Number) -> Number:
192
+ def execute(self, a: Number, b: Number, **kwargs) -> Number:
185
193
  '''
186
194
  Execute the subtraction command.
187
195
 
@@ -189,16 +197,23 @@ class SubtractNumber(Command):
189
197
  :type a: Number
190
198
  :param b: A Number object representing the second number.
191
199
  :type b: Number
200
+ :param kwargs: Additional keyword arguments.
201
+ :type kwargs: dict
192
202
  :return: A Number object representing the difference of a and b.
193
203
  :rtype: Number
194
204
  '''
195
- return ModelObject.new(Number, value=str(a.format() - b.format()))
205
+
206
+ # Subtract formatted values of b from a.
207
+ result = a.format() - b.format()
208
+
209
+ # Return a new Number object with the result.
210
+ return result
196
211
 
197
212
  class MultiplyNumber(Command):
198
213
  '''
199
214
  A command to perform multiplication of two numbers.
200
215
  '''
201
- def execute(self, a: Number, b: Number) -> Number:
216
+ def execute(self, a: Number, b: Number, **kwargs) -> Number:
202
217
  '''
203
218
  Execute the multiplication command.
204
219
 
@@ -206,16 +221,23 @@ class MultiplyNumber(Command):
206
221
  :type a: Number
207
222
  :param b: A Number object representing the second number.
208
223
  :type b: Number
224
+ :param kwargs: Additional keyword arguments.
225
+ :type kwargs: dict
209
226
  :return: A Number object representing the product of a and b.
210
227
  :rtype: Number
211
228
  '''
212
- return ModelObject.new(Number, value=str(a.format() * b.format()))
229
+
230
+ # Multiply the formatted values of a and b.
231
+ result = a.format() * b.format()
232
+
233
+ # Return a new Number object with the result.
234
+ return result
213
235
 
214
236
  class DivideNumber(Command):
215
237
  '''
216
238
  A command to perform division of two numbers.
217
239
  '''
218
- def execute(self, a: Number, b: Number) -> Number:
240
+ def execute(self, a: Number, b: Number, **kwargs) -> Number:
219
241
  '''
220
242
  Execute the division command.
221
243
 
@@ -223,17 +245,26 @@ class DivideNumber(Command):
223
245
  :type a: Number
224
246
  :param b: A Number object representing the second number, must be non-zero.
225
247
  :type b: Number
248
+ :param kwargs: Additional keyword arguments.
249
+ :type kwargs: dict
226
250
  :return: A Number object representing the quotient of a and b.
227
251
  :rtype: Number
228
252
  '''
253
+ # Check if b is zero to avoid division by zero.
229
254
  self.verify(b.format() != 0, 'DIVISION_BY_ZERO')
230
- return ModelObject.new(Number, value=str(a.format() / b.format()))
255
+
256
+ # Divide the formatted values of a by b.
257
+ result = a.format() / b.format()
258
+
259
+ # Return a new Number object with the result.
260
+ return result
261
+
231
262
 
232
263
  class ExponentiateNumber(Command):
233
264
  '''
234
265
  A command to perform exponentiation of two numbers.
235
266
  '''
236
- def execute(self, a: Number, b: Number) -> Number:
267
+ def execute(self, a: Number, b: Number, **kwargs) -> Number:
237
268
  '''
238
269
  Execute the exponentiation command.
239
270
 
@@ -241,45 +272,55 @@ class ExponentiateNumber(Command):
241
272
  :type a: Number
242
273
  :param b: A Number object representing the exponent.
243
274
  :type b: Number
275
+ :param kwargs: Additional keyword arguments.
276
+ :type kwargs: dict
244
277
  :return: A Number object representing a raised to the power of b.
245
278
  :rtype: Number
246
279
  '''
247
- return ModelObject.new(Number, value=str(a.format() ** b.format()))
280
+
281
+ # Exponentiate the formatted value of a by b.
282
+ result = a.format() ** b.format()
283
+
284
+ # Return a new Number object with the result.
285
+ return result
248
286
  ```
249
287
 
250
- These commands perform arithmetic operations on Number objects, using format() to extract numerical values and ModelObject.new to return results as new Number objects. The DivideNumber command includes a verify check to prevent division by zero, referencing a configured error.
288
+ These commands perform arithmetic operations on `Number` objects, using `format()` to extract numerical values and `ModelObject.new` to return results as new `Number` objects. The `DivideNumber` command includes a verify check to prevent division by zero, referencing a configured error.
251
289
 
252
- #### Validation Command in commands/valid.py
253
- Create app/commands/valid.py with the following content:
290
+ #### Validation Command in `commands/valid.py`
291
+ Create `app/commands/valid.py` with the following content:
254
292
 
255
293
  ```python
256
- from ..commands import Command
294
+ from tiferet.commands import *
295
+
257
296
  from ..models.calc import Number
258
297
 
259
298
  class ValidateNumber(Command):
260
299
  '''
261
300
  A command to validate that a value can be a Number object.
262
301
  '''
263
- def execute(self, value: str) -> None:
302
+ def execute(self, value: str, **kwargs) -> None:
264
303
  '''
265
304
  Validate that the input value can be used to create a Number object.
266
305
 
267
306
  :param value: Any string value to validate.
268
307
  :type value: str
308
+ :param kwargs: Additional keyword arguments.
309
+ :type kwargs: dict
269
310
  :raises TiferetError: If the value cannot be a Number.
270
311
  '''
271
312
  try:
272
- ModelObject.new(Number, value=str(value))
313
+ return ModelObject.new(Number, value=str(value))
273
314
  except Exception as e:
274
315
  self.verify(False, 'INVALID_INPUT', value)
275
316
  ```
276
317
 
277
- The ValidateNumber command ensures inputs can be converted to Number objects, raising a configured error for invalid values.
318
+ The `ValidateNumber` command ensures inputs can be converted to `Number` objects, raising a configured error for invalid values.
278
319
 
279
- ### Configuring the Application in configs/config.yaml
280
- The calculator’s behavior is defined in app/configs/config.yaml, which configures container attributes, features, errors, and the application context. This centralized configuration enables Tiferet’s dependency injection container to orchestrate commands and features gracefully.
320
+ ### Configuring the Application in `configs/config.yml`
321
+ The calculator’s behavior is defined in `app/configs/config.yml`, which configures container attributes, features, errors, and the application context. This centralized configuration enables Tiferet’s dependency injection container to orchestrate commands and features gracefully.
281
322
 
282
- Create `app/configs/config.yaml` with the following content:
323
+ Create `app/configs/config.yml` with the following content:
283
324
 
284
325
  ```yaml
285
326
  attrs:
@@ -416,54 +457,66 @@ errors:
416
457
  - lang: es_ES
417
458
  text: 'No se puede dividir por cero'
418
459
 
419
- contexts:
460
+ interfaces:
420
461
  basic_calc:
421
462
  name: Basic Calculator
422
463
  description: Perform basic calculator operations
423
464
  const:
424
- container_config_file: 'app/configs/config.yaml'
425
- feature_config_file: 'app/configs/config.yaml'
426
- error_config_file: 'app/configs/config.yaml'
465
+ container_config_file: 'app/configs/config.yml'
466
+ feature_config_file: 'app/configs/config.yml'
467
+ error_config_file: 'app/configs/config.yml'
427
468
  ```
428
469
 
429
- attrs: Defines container attributes for dependency injection, mapping to command classes (e.g., add_number_cmd to AddNumber).
470
+ `attrs`: Defines container attributes for dependency injection, mapping to command classes (e.g., `add_number_cmd` to `AddNumber`).
430
471
 
472
+ `features`: Configures feature workflows, sequencing validation and arithmetic commands (e.g., `calc.add` validates `a` and `b`, then adds them). The `calc.sqrt` feature reuses `exponentiate_number_cmd` with `b: "0.5"` for square roots.
431
473
 
432
- features: Configures feature workflows, sequencing validation and arithmetic commands (e.g., calc.add validates a and b, then adds them). The calc.sqrt feature reuses exponentiate_number_cmd with b: "0.5" for square roots.
474
+ `errors`: Specifies error messages for `invalid_input` and `division_by_zero`, supporting `en_US` and `es_ES` for multilingual extensibility.
433
475
 
434
- errors: Specifies error messages for invalid_input and division_by_zero, supporting en_US and es_ES for multilingual extensibility.
435
-
436
- contexts: Defines the basic_calc application instance, linking to the configuration file for container, features, and errors.
476
+ `interfaces`: Defines the `basic_calc` interface instance, linking to the configuration file for container, features, and errors.
437
477
 
438
478
  ### Initializing and Demonstrating the Calculator in basic_calc.py
439
- Finally, we initialize the calculator with an initializer script, basic_calc.py, at the project root. This script uses Tiferet’s App class to load the basic_calc context and execute features, demonstrating the calculator’s functionality.
440
- Create basic_calc.py with the following content:
479
+ Finally, we initialize the calculator with an initializer script, `basic_calc.py`, at the project root. This script uses Tiferet’s App class to load the `basic_calc` context and execute features, demonstrating the calculator’s functionality.
480
+ Create `basic_calc.py` with the following content:
441
481
 
442
482
  ```python
443
483
  from tiferet import App
444
484
 
445
485
  # Create new app (manager) instance.
446
- app = App(config_file='app/configs/config.yaml')
486
+ app = App(dict(
487
+ app_repo_module_path='tiferet.proxies.yaml.app',
488
+ app_repo_class_name='AppYamlProxy',
489
+ app_repo_params=dict(
490
+ app_config_file='app/configs/config.yml',
491
+ )
492
+ ))
447
493
 
448
494
  # Execute the add feature to add the values.
449
495
  a = 1
450
496
  b = 2
451
- addition = app.execute_feature('basic_calc', 'calc.add', a=str(a), b=str(b))
497
+ addition = app.run(
498
+ 'basic_calc',
499
+ 'calc.add',
500
+ data=dict(
501
+ a=a,
502
+ b=b,
503
+ )
504
+ )
452
505
 
453
- print(f'{a} + {b} = {addition.format()}')
506
+ print(f'{a} + {b} = {addition}')
454
507
  ```
455
508
 
456
509
  ### Demonstrating the Calculator
457
- To run the calculator, ensure your tiferet_app virtual environment is activated and Tiferet is installed. Execute the initializer script:
510
+ To run the calculator, ensure your `tiferet_app` virtual environment is activated and Tiferet is installed. Execute the initializer script:
458
511
  ```bash
459
512
  python basic_calc
460
513
  ```
461
514
 
462
515
  ### Running the Calculator as a CLI
463
- For a flexible and scriptable interface, the calculator includes a command-line interface (CLI) implemented in calc_cli.py at the project root. This script complements the basic_calc.py test script, which remains available for debugging and simple feature execution. The calc_cli.py script leverages Tiferet’s App class to execute features defined in app/configs/config.yaml, accepting command-line arguments for operations, input values, and locale selection. It supports all calculator features: addition (calc.add), subtraction (calc.subtract), multiplication (calc.multiply), division (calc.divide), exponentiation (calc.exp), and square root (calc.sqrt).
464
- The calc_cli.py script uses Python’s argparse to define subcommands for each feature, with required arguments -a (first number) and -b (second number, except for sqrt). An optional --locale flag selects the error message language (en_US or es_ES, defaulting to en_US). The script executes the specified feature in the basic_calc context, returning a Number object whose format() method yields the result as an integer or float.
516
+ For a flexible and scriptable interface, the calculator includes a command-line interface (CLI) implemented in `calc_cli.py` at the project root. This script complements the `basic_calc.py` test script, which remains available for debugging and simple feature execution. The `calc_cli.py` script leverages Tiferet’s App class to execute features defined in `app/configs/config.yml`, accepting command-line arguments for operations and input values. It supports all calculator features: addition (calc.add), subtraction (calc.subtract), multiplication (`calc.multiply`), division (`calc.divide`), exponentiation (`calc.exp`), and square root (`calc.sqrt`).
517
+ The `calc_cli.py` script uses Python’s argparse to define subcommands for each feature, with required arguments `-a` (first number) and `-b` (second number, except for sqrt). The script executes the specified feature in the `basic_calc` context, returning the result as an integer or float.
465
518
 
466
- Create calc_cli.py with the following content:
519
+ Create `calc_cli.py` with the following content:
467
520
  ```python
468
521
  import argparse
469
522
  from tiferet import App, TiferetError
@@ -471,8 +524,7 @@ from tiferet import App, TiferetError
471
524
  def main():
472
525
  """Parse CLI arguments and execute the calculator feature."""
473
526
  parser = argparse.ArgumentParser(description="Basic Calculator CLI using Tiferet")
474
- parser.add_argument('--config', default='app/configs/config.yaml', help='Path to config file')
475
- parser.add_argument('--locale', default='en_US', choices=['en_US', 'es_ES'], help='Language for error messages')
527
+ parser.add_argument('--config', default='app/configs/config.yml', help='Path to config file')
476
528
 
477
529
  subparsers = parser.add_subparsers(dest='operation', required=True, help='Calculator operation')
478
530
 
@@ -494,9 +546,6 @@ def main():
494
546
 
495
547
  args = parser.parse_args()
496
548
 
497
- # Create app instance
498
- app = App(config_file=args.config)
499
-
500
549
  # Map operation to feature ID
501
550
  feature_map = {
502
551
  'add': 'calc.add',
@@ -513,16 +562,27 @@ def main():
513
562
  if args.operation != 'sqrt':
514
563
  params['b'] = str(args.b)
515
564
 
565
+ # Create app instance
566
+ # # Assume the default app settings is defined in a YAML file
567
+ settings = dict(
568
+ app_repo_module_path='tiferet.proxies.yaml.app',
569
+ app_repo_class_name='AppYamlProxy',
570
+ app_repo_params=dict(
571
+ app_config_file=args.config,
572
+ )
573
+ )
574
+ app = App(settings)
575
+
516
576
  try:
517
577
  # Execute feature with locale
518
- result = app.execute_feature('basic_calc', feature_id, locale=args.locale, **params)
578
+ result = app.run('basic_calc', feature_id, data=params)
519
579
 
520
580
  # Display result
521
581
  if args.operation == 'sqrt':
522
- print(f"√{args.a} = {result.format()}")
582
+ print(f"√{args.a} = {result}")
523
583
  else:
524
584
  op_symbol = {'add': '+', 'subtract': '-', 'multiply': '*', 'divide': '/', 'exp': '^'}[args.operation]
525
- print(f"{args.a} {op_symbol} {args.b} = {result.format()}")
585
+ print(f"{args.a} {op_symbol} {args.b} = {result}")
526
586
  except TiferetError as e:
527
587
  print(f"Error: {e.message}")
528
588
  except Exception as e:
@@ -551,10 +611,10 @@ python calc_cli.py divide -a 5 -b 0
551
611
  # Output: Error: Cannot divide by zero
552
612
  ```
553
613
 
554
- The calc_cli.py script is scriptable and integrates easily with shell scripts or external systems, making it a versatile interface for the calculator. For quick testing or debugging, use basic_calc.py, which executes a single feature (e.g., calc.add) with hardcoded values. The CLI’s argument-driven design allows precise control over operations, with error messages tailored to the selected locale, showcasing Tiferets multilingual capabilities.
614
+ The `calc_cli.py` script is scriptable and integrates easily with shell scripts or external systems, making it a versatile interface for the calculator. For quick testing or debugging, use `basic_calc.py`, which executes a single feature (e.g., `calc.add`) with hardcoded values. The CLI’s argument-driven design allows precise control over operations, showcasing Tiferet's flexibility in run-time environments.
555
615
 
556
616
  ## Conclusion
557
- This tutorial has woven together the elegance of Tiferet’s Domain-Driven Design framework to create a robust and extensible basic calculator. From defining the immutable Number model to crafting command classes for arithmetic and validation, configuring features and errors, and launching the application via both a test script (basic_calc.py) and a CLI (calc_cli.py), you’ve experienced Tiferet’s balance of clarity and power. The configuration-driven approach, with dependency injection and multilingual error handling, embodies the Kabbalistic beauty of purposeful design, making the calculator both functional and a joy to develop.
617
+ This tutorial has woven together the elegance of Tiferet’s Domain-Driven Design framework to create a robust and extensible basic calculator. From defining the immutable Number model to crafting command classes for arithmetic and validation, configuring features and errors, and launching the application via both a test script (`basic_calc.py`) and a CLI (`calc_cli.py`), you’ve experienced Tiferet’s balance of clarity and power. The configuration-driven approach, with dependency injection and multilingual error handling, embodies the Kabbalistic beauty of purposeful design, making the calculator both functional and a joy to develop.
558
618
 
559
- With the foundation laid, you can extend this application in many directions. Consider adding a terminal user interface (TUI) in a new script, calc_tui.py, to wrap calc_cli.py for interactive menu-driven operation. Explore a scientific calculator context (sci_calc) with advanced features like trigonometric functions, reusing the Number model or introducing new ones. Or integrate the calculator into larger systems, leveraging Tiferet’s modularity for domains like financial modeling or data processing. Whatever path you choose, Tiferet’s graceful framework will guide you to solutions that resonate with both purpose and precision.
560
- To continue your journey, try running additional features with calc_cli.py, experiment with new feature configurations in app/configs/config.yaml, or dive into Tiferet’s documentation for advanced DDD techniques. The beauty of Tiferet lies in its ability to transform complexity into clarity—may your creations reflect this harmony.
619
+ With the foundation laid, you can extend this application in many directions. Consider adding a terminal user interface (TUI) in a new script, `calc_tui.py`, to wrap `calc_cli.py` for interactive menu-driven operation. Explore a scientific calculator context (`sci_calc`) with advanced features like trigonometric functions, reusing the `Number` model or introducing new ones. Or integrate the calculator into larger systems, leveraging Tiferet’s modularity for domains like financial modeling or data processing. Whatever path you choose, Tiferet’s graceful framework will guide you to solutions that resonate with both purpose and precision.
620
+ To continue your journey, try running additional features with `calc_cli.py`, experiment with new feature configurations in `app/configs/config.yml`, or dive into Tiferet’s documentation for advanced DDD techniques. The beauty of Tiferet lies in its ability to transform complexity into clarity—may your creations reflect this harmony.
@@ -9,7 +9,7 @@ config = {
9
9
  'url': r'https://github.com/greatstrength/app',
10
10
  'download_url': r'https://github.com/greatstrength/app',
11
11
  'author_email': 'andrew@greatstrength.me',
12
- 'version': '1.0.0-beta.0',
12
+ 'version': '1.0.0-beta.2',
13
13
  'license': 'BSD 3',
14
14
  'install_requires': [
15
15
  'schematics>=2.1.1',
@@ -101,8 +101,6 @@ class FeatureContext(object):
101
101
  except Exception as e:
102
102
  if not pass_on_error:
103
103
  raise e
104
- finally:
105
- print(f'Command {command.attribute_id} execution failed: {e}' if 'e' in locals() else '')
106
104
 
107
105
  # If a data key is provided, store the result in the request data.
108
106
  if data_key:
@@ -140,21 +138,25 @@ class FeatureContext(object):
140
138
  # Execute the feature with the request and commands.
141
139
  for index, cmd in enumerate(commands):
142
140
 
141
+ # Get the feature command from the feature.
142
+ feature_command = feature.commands[index]
143
+
143
144
  # Parse the command parameters
144
145
  params = {
145
146
  param: self.feature_service.parse_parameter(value, request)
146
- for param, value in feature.commands[index].parameters.items()
147
+ for param, value in feature_command.parameters.items()
147
148
  }
148
149
 
149
150
  # Execute the command with the request data and parameters.
150
151
  self.handle_command(
151
152
  cmd,
152
153
  request,
154
+ data_key=feature_command.data_key,
155
+ pass_on_error=feature_command.pass_on_error,
153
156
  **params,
154
157
  features=self.feature_service,
155
158
  container=self.container,
156
159
  cache=self.cache,
157
160
  **kwargs
158
161
  )
159
-
160
162
 
@@ -22,10 +22,8 @@ class ContainerHandler(ContainerService):
22
22
  '''
23
23
  Initialize the container handler.
24
24
 
25
- :param name: The name of the container.
26
- :type name: str
27
- :param dependencies: The dependencies.
28
- :type dependencies: dict
25
+ :param container_repo: The container repository to use for managing container attributes.
26
+ :type container_repo: ContainerRepository
29
27
  '''
30
28
 
31
29
  # Assign the container repository.
@@ -69,15 +67,20 @@ class ContainerHandler(ContainerService):
69
67
  # If constants are provided, clean the parameters using the parse_parameter command.
70
68
  constants = {k: parse_parameter.execute(v) for k, v in constants.items()}
71
69
 
72
- # Iterate through each attribute to clean parameter dictionaries.
73
- # For each attribute, parse its parameters and add them to the constants dictionary.
74
- # For each dependency, parse its parameters and add them to the constants dictionary.
70
+ # Iterate through each attribute.
75
71
  for attr in attributes:
76
- constants.update({k: parse_parameter.execute(v) for k, v in attr.parameters.items()})
77
- dependency = attr.get_dependency(flags)
72
+
73
+ # If flags are provided, check for dependencies with those flags.
74
+ dependency = attr.get_dependency(*flags)
75
+
76
+ # Update the constants dictionary with the parsed parameters from the dependency or the attribute itself.
78
77
  if dependency:
79
78
  constants.update({k: parse_parameter.execute(v) for k, v in dependency.parameters.items()})
80
79
 
80
+ # If no dependency is found, use the attribute's parameters.
81
+ else:
82
+ constants.update({k: parse_parameter.execute(v) for k, v in attr.parameters.items()})
83
+
81
84
  # Return the updated constants dictionary.
82
85
  return constants
83
86
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tiferet
3
- Version: 1.0.0b0
3
+ Version: 1.0.0b2
4
4
  Summary: A multi-purpose application framework embodying beauty in form.
5
5
  Home-page: https://github.com/greatstrength/app
6
6
  Download-URL: https://github.com/greatstrength/app
File without changes
File without changes
File without changes
File without changes