Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Workflow Interface] Rename and Refactor WorkspaceExport into NotebookTools #1364

Open
wants to merge 36 commits into
base: develop
Choose a base branch
from

Conversation

refai06
Copy link
Contributor

@refai06 refai06 commented Feb 11, 2025

Description:

This PR refactors WorkspaceExport functionality into distinct classes: NotebookTools and CodeAnalyzer. This change is intended to improve code organization, maintainability, and readability to user.

Change Description:

NotebookTools:

  • The main interface for workspace export and management operations.

  • Handles two export interfaces:

    export(): Aggregator-based workflow export.

    export_federated(): FederatedRuntime-specific export.

  • Responsible for generating configuration and requirements files.

CodeAnalyzer:

  • A dedicated helper class for code analysis and transformation.

  • Provides utilities for converting notebooks to Python scripts, analysing and extracting key information, including flow details, configurations, runtime details.

Note:

  • NotebookTools provides the user interface (for Aggregator based workflow) and internally utilizes the CodeAnalyzer class.

  • NotebookTools replaces the WorkspaceExport module.

Deleted:

  • openfl/experimental/workflow/workspace_export/export.py

Files Added:

  • openfl/experimental/workflow/notebooktools/notebook_tools.py
  • openfl/experimental/workflow/notebooktools/code_analyzer.py

Files Modified:

  • openfl-tutorials/experimental/workflow/1001_Workspace_Creation_from_JupyterNotebook.ipynb
  • openfl-tutorials/experimental/workflow/Vertical_FL/TwoPartyWorkspaceCreation.ipynb
  • openfl/experimental/workflow/interface/cli/workspace.py
  • openfl/experimental/workflow/runtime/federated_runtime.py

Verification:

Following tutorials are validated to ensure the refactoring is working fine

  • openfl-tutorials/experimental/workflow/FederatedRuntime/301_MNIST_Watermaking
  • openfl-tutorials/experimental/workflow/1001_Workspace_Creation_from_JupyterNotebook.ipynb

Test Case:

Following test cases are added which validates the NotebookTools export() and export_federated() functionality

  • tests/openfl/experimental/workflow/NotebookTools/tescase_export
  • tests/openfl/experimental/workflow/NotebookTools/testcase_export_federated

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could having an overloaded NotebookTools.export function contribute to a more streamlined user interface? With the introduction of SecureFederatedRuntime (and other runtime environments in the future), users could leverage a single export call (with varying parameters), allowing the system to internally determine the appropriate export flow for each runtime.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@teoparvanov @scngupta-dsp What are your thoughts on this?

Copy link
Collaborator

@teoparvanov teoparvanov Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, @theakshaypant - indeed, the current interface would not scale very well with the addition of more runtimes...

@refai06 refai06 marked this pull request as ready for review February 20, 2025 12:56
@refai06 refai06 changed the title [WIP] [Workflow Interface] Rename and Refactor WorkspaceExport into NotebookTools [Workflow Interface] Rename and Refactor WorkspaceExport into NotebookTools Feb 20, 2025
Signed-off-by: refai06 <[email protected]>
@@ -0,0 +1,5 @@
# Copyright (C) 2020-2021 Intel Corporation
# Licensed subject to the terms of the separately executed evaluation license agreement between Intel Corporation and you.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed - Instead of using expected. Can we have proper asserts or conditions in the code. So that hardcoded files just to compare is not needed.

import pytest
from openfl.experimental.workflow.notebooktools import NotebookTools

class bcolors:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use testing framework like unittest or pytest to run.

Copy link
Collaborator

@teoparvanov teoparvanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I understand the intention of breaking down the original WorkspaceExport class into smaller and better encapsulated entities, I think this PR has gone a bit sideways...

Copy link
Collaborator

@teoparvanov teoparvanov Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, @theakshaypant - indeed, the current interface would not scale very well with the addition of more runtimes...

Comment on lines +71 to +105
@classmethod
def export_federated(
cls, notebook_path: str, output_workspace: str, director_fqdn: str, tls: bool = False
) -> Tuple[str, str]:
"""Exports workspace for FederatedRuntime.

Args:
notebook_path (str): Path to the Jupyter notebook.
output_workspace (str): Path for the generated workspace directory.
director_fqdn (str): Fully qualified domain name of the director node.
tls (bool, optional): Whether to use TLS for the connection.

Returns:
Tuple[str, str]: A tuple containing:
(archive_path, flow_class_name).
"""
instance = cls(notebook_path, output_workspace)
instance._generate_requirements()
instance._generate_plan_yaml(director_fqdn, tls)
instance._clean_generated_workspace()
print_tree(output_workspace, level=2)
return instance._generate_experiment_archive()

@classmethod
def export(cls, notebook_path: str, output_workspace: str) -> None:
"""Exports workspace to output_workspace.
Args:
notebook_path (str): Path to the Jupyter notebook.
output_workspace (str): Path for the generated workspace directory.
"""
instance = cls(notebook_path, output_workspace)
instance._generate_requirements()
instance._generate_plan_yaml()
instance._generate_data_yaml()
print_tree(output_workspace, level=2)
Copy link
Collaborator

@teoparvanov teoparvanov Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to admit that I don't understand very well what's going on here... You have a NotebookTools class that maintains some internal state (self.notebook_path, self.output_workspace_path, etc.). At the same time the public methods of this class are "static" (@classmethod).

Going into more detail, I also have trouble grasping the semantic difference between export() and export_federated(). Is it so significant that it warrants a separate method for the two? If you need different behaviors between LocalRuntime and FederatedRuntime, you could maybe consider creating sub-classes of NotebookTools for those two cases? As pointed out by @theakshaypant, this would also enable accommodating SecureFederatedRuntime down the road. However, I'm not sure if the differences are indeed that significant to warrant the added complexity in the class hierarchy...

WDYT?

logger = getLogger(__name__)


class NotebookTools:
Copy link
Collaborator

@teoparvanov teoparvanov Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name NotebookTools implies an amorphous collection of tools/methods, rather than a well-encapsulated entity. I suggest renaming this class to something like FLWorkflowNotebook, with a single export_to(workspace_output_path: str) public method.

Here is an illustration of the proposed API and its usage:

nb = FLWorkflowNotebook("/home/dev/experiment.ipynb")
nb.export_to("/home/dev/fl_workspace")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants