diff --git a/code/episode_6/advanced_pydantic/src/advanced_pydantic/main.py b/code/episode_6/advanced_pydantic/src/advanced_pydantic/main.py index 33bad76a79e46e35eaf17ab0f35aa1f8b8daf989..46ba84e8a62f2c9ca81e48f4dd83049293f9b18e 100644 --- a/code/episode_6/advanced_pydantic/src/advanced_pydantic/main.py +++ b/code/episode_6/advanced_pydantic/src/advanced_pydantic/main.py @@ -41,7 +41,7 @@ def main() -> None: # Example input user_data = { "id": 2, - "name": "Alice", + "name": "alice", "addresses": [{"street": "123 Main St", "city": "New York", "zip_code": "10001", "type": "home"}], } diff --git a/code/episode_6/pydantic_mvvm/src/trame_with_pydantic/app/view_models/main.py b/code/episode_6/pydantic_mvvm/src/trame_with_pydantic/app/view_models/main.py index 80eb206f23b9d46727ace2f1cd8da623f38b1a28..dfcba7aec8de119af426023b44e026f33f6a6032 100644 --- a/code/episode_6/pydantic_mvvm/src/trame_with_pydantic/app/view_models/main.py +++ b/code/episode_6/pydantic_mvvm/src/trame_with_pydantic/app/view_models/main.py @@ -21,4 +21,4 @@ class MainViewModel: print(f"model fields updated: {results['updated']}") def update_view(self) -> None: - self.settings_bind.update_view(self.settings) + self.settings_bind.update_in_view(self.settings) diff --git a/episodes/06-Advanced-Data-Modeling.md b/episodes/06-Advanced-Data-Modeling.md index 054a97cff7ac5c645eec09723ef921c6171aa572..3a63b97f18930070eda03b204b9cd8e22e47f03a 100755 --- a/episodes/06-Advanced-Data-Modeling.md +++ b/episodes/06-Advanced-Data-Modeling.md @@ -58,18 +58,34 @@ Key Features of Pydantic: * **Improved Code Readability:** Makes code easier to understand and maintain by explicitly defining data models. Type hints make it clear what type of data is expected for each field. -## Setup I +## Create a new CLI project Let\'s start by setting up a new application from the template. -Create a CLI project answering the `copier` questions, use `Advanced Pydantic` for the project name and use defaults for all other questions. +To clone the template application, run the following command: ```bash copier copy https://code.ornl.gov/ndip/project-templates/nova-application-template.git advanced_pydantic +``` + +This command will download the template to a directory called `advanced_pydantic`. Copier will prompt you with a series of questions. Please answer the questions as follows: + +* **What is your project name?** + + > Enter `Advanced Pydantic` + +* **All other questions** + + > Press enter to accept the default. + +After that, go into the created folder and install project dependencies: + +```bash cd advanced_pydantic poetry install ``` + ## How Pydantic Works Pydantic uses Python type hints to define data models. When you create an instance of a Pydantic model, Pydantic automatically validates the input data against the defined types and constraints. @@ -182,7 +198,7 @@ poetry run app For easier integration with the NOVA framework, where model field information is used for displaying and validating GUI elements, we recommend avoiding overly complex nested structures. In particular, lists of lists are currently not supported. :::::::::::::::::::::::::::::::::::::::::::::::::: -## Implement custom validation logic for a single field. +## Implement custom validation logic for a single field Sometimes, simple validation like checking the minimum length is not enough. In such cases, you can write a custom validation function for a specific field. @@ -221,7 +237,7 @@ Note that we used the mode="**after**" option for the validator. This ensures th :::::::::::::::::::::::::::::::::::::::::::::::::: -## Implement custom validation logic for the whole model. +## Implement custom validation logic for the whole model In some cases, you may need to validate the entire model, not just individual fields. This can be done by writing a custom validation function for the whole model using the `@model_validator` decorator. @@ -255,18 +271,58 @@ def main() -> None: This code will raise a ValueError because the name ("alice") does not start with a capital letter, while the id is even. -## Setup II +## Create a simple Trame application -Now, let\'s create a simple Trame GUI, use `Trame With Pydantic` for the project name, -set up a Trame-based GUI application based on MVVM and use defaults for all other questions. +Now, let\'s create a simple Trame-based GUI application. + +To clone the template application, run the following command: ```bash -cd .. # if you are in advanced_pydantic folder copier copy https://code.ornl.gov/ndip/project-templates/nova-application-template.git pydantic_mvvm +``` + +This command will download the template to a directory called `pydantic_mvvm`. Copier will prompt you with a series of questions. Please answer the questions as follows: + +* **What is your project name?** + + > Enter `Advanced Pydantic` + +* **What is your Python package name (use Python naming conventions)?** + + > Press enter to accept the default. + +* **Do you want to install Mantid for your project?** + + > Enter `n` + +* **Are you developing a GUI application using MVVM pattern?** + + > Enter `y` + +* **Which library will you use?** + + > Select `Trame` + +* **Do you want a template with multiple tabs?** + + > Enter `n` + +* **Publish to PyPI?** + + > Enter `n` + +* **Publish documentation to readthedocs.io?** + + > Enter `n` + +After that, go into the created folder and install project dependencies: + +```bash cd pydantic_mvvm poetry install ``` + ## Using Pydantic models in NOVA framework One of the great features of the NOVA Framework is that it allows an application to leverage Pydantic models to automatically validate UI elements. Let\'s walk through what that looks like in code. @@ -294,7 +350,7 @@ class MainViewModel: self.settings_bind = binding.new_bind(self.settings) def update_view(self): - self.settings_bind.update_view(self.settings) + self.settings_bind.update_in_view(self.settings) ``` In your view, remove all other fields and add the following InputField (modify `src/trame_with_pydantic/app/views/main.py`): @@ -332,6 +388,22 @@ class MainViewModel: The function will receive a dictionary containing lists of updated or invalid fields. Note that if a validation error occurs, the model will not be updated, leading to a discrepancy between the values displayed in the UI and those in the model. +::::::::::::::::::::::::::::::::::::::: challenge +**Model validation** +Change the model validation rule so that it does not allow user `alice`. +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge +**Pydantic Field** +Add another Pydantic field - a float value that should be positive, to the model. +:::::::::::::::::::::::::::::::::::::::::::::::::: + + +::::::::::::::::::::::::::::::::::::::: challenge +**Value auto fix** +In the GUI application, set the port to the default value if a user enters an incorrect value in the interface. +:::::::::::::::::::::::::::::::::::::::::::::::::: + :::::::::::::::::::::::::::::::::::::::: keypoints - Data Validation has many key benefits, such as protecting against errors, data corruption, and vulnerabilities. - Pydantic is a powerful Python library used to define data models and enforce data validation.