In this section, we will start using the `nova-galaxy` library to interact with the NDIP platform and run a neutron analysis tool. First, ensure you have set your `GALAXY_URL` and `GALAXY_API_KEY` as environment variables, as explained in the notes at the end of this episode. We also need to add `nova-galaxy` as a project dependency.
From the command line, type `poetry add nova-galaxy@^0.4.0`. This command will add the nova-galaxy library to the pyproject.toml file as a project dependency. Then run `poetry install` to update your project dependencies.
From the command line, type `poetry add nova-galaxy@^0.7.0`. This command will add the nova-galaxy library to the pyproject.toml file as a project dependency. Then run `poetry install` to update your project dependencies.
## Interacting with NDIP via `nova-galaxy`
@@ -60,6 +60,7 @@ To get started, let\'s create the Fractal class. Create an empty file at `src/no
***Imports**: The `Fractal Class` will start by importing the necessary classes from `nova-galaxy`:
```python
import os
from nova.galaxy import Connection, Parameters, Tool
```
@@ -77,6 +78,7 @@ To get started, let\'s create the Fractal class. Create an empty file at `src/no
* **Instantiate `Connection`, `Tool`, and `Parameters`**: We create instances of the `Connection`, `Tool`, and `Parameters` classes:
@@ -86,14 +88,15 @@ To get started, let\'s create the Fractal class. Create an empty file at `src/no
Note that we create a `Tool` object with the `id="neutrons_fractal"`. This tells `nova-galaxy` which NDIP tool we want to run. The obvious question at this point is how do we know the id of the tool and what parameters it expects? We can look at the tool\'s launch page in calvera for some hints but ultimately we have to look at the tool\'s [xml file](https://code.ornl.gov/ndip/galaxy-tools/-/blob/dev/tools/neutrons/test_tools/fractal.xml?ref_type=heads).
* **Connect and Run the Tool**: The `with conn.connect() as galaxy_connection:` block establishes a connection to NDIP and ensures proper handling of the connection:
@@ -103,13 +106,15 @@ We are now going to modify the existing `main.py` file. Change the main method t
***Instantiate and Run**: In the `main()` function, we create an instance of `Fractal` and call the `run_fractal_tool()` method, wrapped in a `try...except` block for basic error handling:
Let\'s see how to implement the MVVM pattern using `nova-mvvm` and incorporate Pydantic for data validation.
**1. Adding Fractal to the ViewModel (`src/nova_tutorial/view_models/main.py`):**
**1. Adding Fractal to the ViewModel (`src/nova_tutorial/app/view_models/main.py`):**
***Running our Model**: We start by adding a method to our ViewModel which will run the Fractal tool.
***Running our Model**: We start by adding a method to bottom of our ViewModel which will run the Fractal tool.
```python
defrun_fractal(self)->None:
@@ -151,18 +151,20 @@ Let\'s see how to implement the MVVM pattern using `nova-mvvm` and incorporate P
self.update_view()
```
**2. Updating our Fractal Class for pydantaic and MVVM (`src/nova/tutorial/models/fractal.py**
**2. Updating our Fractal Class for pydantaic and MVVM (`src/nova_tutorial/app/models/fractal.py**
***Adding new imports**: We need to add some imports for pydantic and working with base64 encondings to deal with the image.
***Adding new imports**: We need to add some imports for pydantic and working with base64 encondings to deal with the image. Modify your import block to match below.
```python
importos
frombase64importb64encode
fromtypingimportLiteral
frompydanticimportBaseModel,Field
fromnova.galaxyimportConnection,Parameters,Tool
```
***Update class variables:** Now we'll update fractal_type to support pydantic and add an image variable to store the image. Modify the variable declarations to the following:
***Update class variables:** Now we'll update fractal_type and other class variables to support pydantic. We'll also add an image variable to store the image. Modify the variable declarations to the following:
```python
classFractal(BaseModel):
@@ -182,7 +184,21 @@ Let\'s see how to implement the MVVM pattern using `nova-mvvm` and incorporate P
@@ -216,8 +233,14 @@ Let\'s see how to implement the MVVM pattern using `nova-mvvm` and incorporate P
vuetify.VTab("Sample Tab 2",value=3)
```
**5. Modify the tab panel content (`src/nova_tutorial/views/tab_content_panel.py`):**
Add our new Fractal Tab to the tab content panel.
**6. Modify the tab panel content (`src/nova_tutorial/app/views/tab_content_panel.py`):**
***Add FractalTab to imports**: Import the newly created FractalTab class into our tab_content_panel.
```python
from.fractal_tabimportFractalTab# Import the FractalTab
```
***Add the Fractal Tab to our existing tabs**: Add the Fractal Tab lines to the vuetify.VWindow section and modify the values.
```python
withvuetify.VWindow(v_model="active_tab"):
@@ -229,6 +252,30 @@ Let\'s see how to implement the MVVM pattern using `nova-mvvm` and incorporate P
SampleTab2()
```
**7. `main.py` - Calling the Model (`src/nova_tutorial/app/main.py`):**
We are now going to modify the existing `main.py` file. Change the main method to match the code below.
***Instantiate and Run**: In the `main()` function, we create an instance of `Fractal` and call the `run_fractal_tool()` method, wrapped in a `try...except` block for basic error handling:
```python
importsys
from.models.fractalimportFractal
defmain()->None:
kwargs={}
from.views.mainimportMainApp
app=MainApp()
forarginsys.argv[2:]:
try:
key,value=arg.split("=")
kwargs[key]=int(value)
exceptException:
pass
app.server.start(**kwargs)
```
## Running the application
To run the code, use the following command in the top level of your `nova_tutorial` project:
@@ -241,7 +288,7 @@ You should see `Fractal tool finished successfully.` printed to the console, alt
* In `FractalViewModel` in `src/nova_tutorial/view_models/fractal_view_model.py`, modify the `update_fractal_programmatically` function from the previous exercise to use an *invalid* fractal type:
* In `FractalViewModel` in `src/nova_tutorial/app/view_models/fractal_view_model.py`, modify the `update_fractal_programmatically` function from the previous exercise to use an *invalid* fractal type:
```python
defupdate_fractal_programmatically(new_type:str):
self.fractal_type=new_type# Use the setter which includes validation
@@ -260,7 +307,7 @@ You should see `Fractal tool finished successfully.` printed to the console, alt
::::::::::::::::::::::::::::::::::::::: challenge
**Inspect ViewModel State**
* In `src/nova_tutorial/view_models/fractal_view_model.py`, add `print` statements within the `FractalViewModel.__init__` method to print the initial values of `self._fractal_type`, `self._job_status`, and `self._message`.
* In `src/nova_tutorial/app/view_models/fractal_view_model.py`, add `print` statements within the `FractalViewModel.__init__` method to print the initial values of `self._fractal_type`, `self._job_status`, and `self._message`.
* Run the application (`poetry run app`). Observe the output in the console. Verify that the initial values are printed as expected.
* Now, modify the `FractalViewModel.__init__` method to change the initial value of `self._message` to "Application starting...". Run the application again and confirm that the printed initial message has changed.
@@ -268,7 +315,7 @@ You should see `Fractal tool finished successfully.` printed to the console, alt
::::::::::::::::::::::::::::::::::::::: challenge
**Programmatic State Update and Binding:**
* In `FractalViewModel` in `src/nova_tutorial/view_models/fractal_view_model.py`, after the line `self.fractal_type_bind = binding.new_bind(...)` in `__init__`, add the following lines:
* In `FractalViewModel` in `src/nova_tutorial/app/view_models/fractal_view_model.py`, after the line `self.fractal_type_bind = binding.new_bind(...)` in `__init__`, add the following lines:
```python
print("Initial fractal type:",self._fractal_type)# Print initial value
@@ -75,7 +75,7 @@ Layouts are responsible for arraging your content in a consistent manner. In Tra
`nova-trame` provides a basic layout and theme that you can access via the `ThemedApp` class. The template app will setup your main view class to inherit from `ThemedApp` already, so let\'s look at how the layout is defined and how we can add content to slots.
**1. `nova_tutorial/views/main.py`:**
**1. `nova_tutorial/app/views/main.py`:**
```python
classMainApp(ThemedApp):
@@ -215,7 +215,7 @@ For a more detailed explanation of how to work with our layout and theme, please
Now, let\'s add some UI components to the Sample Tabs in our application to demonstrate how to use these components. We\'ll modify the `sample_tab_1.py` and `sample_tab_2.py` files to include these components.