From 538908bbf632f75d5f060fb299dcbee709d300ad Mon Sep 17 00:00:00 2001 From: Taner Topal Date: Tue, 20 Feb 2024 12:25:04 +0100 Subject: [PATCH 1/2] Add `flwr` CLI (#2942) Co-authored-by: Javier Co-authored-by: Daniel J. Beutel --- pyproject.toml | 2 + src/py/flwr/cli/__init__.py | 15 ++ src/py/flwr/cli/app.py | 35 +++++ src/py/flwr/cli/example.py | 64 +++++++++ src/py/flwr/cli/new/__init__.py | 21 +++ src/py/flwr/cli/new/new.py | 130 ++++++++++++++++++ src/py/flwr/cli/new/new_test.py | 93 +++++++++++++ src/py/flwr/cli/new/templates/__init__.py | 15 ++ .../flwr/cli/new/templates/app/README.md.tpl | 33 +++++ src/py/flwr/cli/new/templates/app/__init__.py | 15 ++ .../cli/new/templates/app/code/__init__.py | 15 ++ .../new/templates/app/code/__init__.py.tpl | 1 + .../templates/app/code/client.pytorch.py.tpl | 1 + .../app/code/client.tensorflow.py.tpl | 1 + .../templates/app/code/server.pytorch.py.tpl | 1 + .../app/code/server.tensorflow.py.tpl | 1 + .../cli/new/templates/app/flower.toml.tpl | 10 ++ .../app/requirements.pytorch.txt.tpl | 4 + .../app/requirements.tensorflow.txt.tpl | 4 + src/py/flwr/cli/utils.py | 54 ++++++++ 20 files changed, 515 insertions(+) create mode 100644 src/py/flwr/cli/__init__.py create mode 100644 src/py/flwr/cli/app.py create mode 100644 src/py/flwr/cli/example.py create mode 100644 src/py/flwr/cli/new/__init__.py create mode 100644 src/py/flwr/cli/new/new.py create mode 100644 src/py/flwr/cli/new/new_test.py create mode 100644 src/py/flwr/cli/new/templates/__init__.py create mode 100644 src/py/flwr/cli/new/templates/app/README.md.tpl create mode 100644 src/py/flwr/cli/new/templates/app/__init__.py create mode 100644 src/py/flwr/cli/new/templates/app/code/__init__.py create mode 100644 src/py/flwr/cli/new/templates/app/code/__init__.py.tpl create mode 100644 src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl create mode 100644 src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl create mode 100644 src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl create mode 100644 src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl create mode 100644 src/py/flwr/cli/new/templates/app/flower.toml.tpl create mode 100644 src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl create mode 100644 src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl create mode 100644 src/py/flwr/cli/utils.py diff --git a/pyproject.toml b/pyproject.toml index 297574ef67ed..065d5bc1f216 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ exclude = [ ] [tool.poetry.scripts] +flwr = "flwr.cli.app:app" flower-driver-api = "flwr.server:run_driver_api" flower-fleet-api = "flwr.server:run_fleet_api" flower-superlink = "flwr.server:run_superlink" @@ -67,6 +68,7 @@ protobuf = "^4.25.2" cryptography = "^41.0.2" pycryptodome = "^3.18.0" iterators = "^0.0.2" +typer = { version = "^0.9.0", extras=["all"] } # Optional dependencies (VCE) ray = { version = "==2.6.3", optional = true } pydantic = { version = "<2.0.0", optional = true } diff --git a/src/py/flwr/cli/__init__.py b/src/py/flwr/cli/__init__.py new file mode 100644 index 000000000000..d4d3b8ac4d48 --- /dev/null +++ b/src/py/flwr/cli/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface.""" diff --git a/src/py/flwr/cli/app.py b/src/py/flwr/cli/app.py new file mode 100644 index 000000000000..dc390de03547 --- /dev/null +++ b/src/py/flwr/cli/app.py @@ -0,0 +1,35 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface.""" + +import typer + +from .example import example +from .new import new + +app = typer.Typer( + help=typer.style( + "flwr is the Flower command line interface.", + fg=typer.colors.BRIGHT_YELLOW, + bold=True, + ), + no_args_is_help=True, +) + +app.command()(new) +app.command()(example) + +if __name__ == "__main__": + app() diff --git a/src/py/flwr/cli/example.py b/src/py/flwr/cli/example.py new file mode 100644 index 000000000000..625ca8729640 --- /dev/null +++ b/src/py/flwr/cli/example.py @@ -0,0 +1,64 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface `example` command.""" + +import json +import os +import subprocess +import tempfile +import urllib.request + +from .utils import prompt_options + + +def example() -> None: + """Clone a Flower example. + + All examples available in the Flower repository are available through this command. + """ + # Load list of examples directly from GitHub + url = "https://api.github.com/repos/adap/flower/git/trees/main" + with urllib.request.urlopen(url) as res: + data = json.load(res) + examples_directory_url = [ + item["url"] for item in data["tree"] if item["path"] == "examples" + ][0] + + with urllib.request.urlopen(examples_directory_url) as res: + data = json.load(res) + example_names = [ + item["path"] for item in data["tree"] if item["path"] not in [".gitignore"] + ] + + example_name = prompt_options( + "Please select example by typing in the number", + example_names, + ) + + with tempfile.TemporaryDirectory() as tmpdirname: + subprocess.check_output( + [ + "git", + "clone", + "--depth=1", + "https://github.com/adap/flower.git", + tmpdirname, + ] + ) + examples_dir = os.path.join(tmpdirname, "examples", example_name) + subprocess.check_output(["mv", examples_dir, "."]) + + print() + print(f"Example ready to use in {os.path.join(os.getcwd(), example_name)}") diff --git a/src/py/flwr/cli/new/__init__.py b/src/py/flwr/cli/new/__init__.py new file mode 100644 index 000000000000..a973f47021c3 --- /dev/null +++ b/src/py/flwr/cli/new/__init__.py @@ -0,0 +1,21 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface `new` command.""" + +from .new import new as new + +__all__ = [ + "new", +] diff --git a/src/py/flwr/cli/new/new.py b/src/py/flwr/cli/new/new.py new file mode 100644 index 000000000000..d5db6091344d --- /dev/null +++ b/src/py/flwr/cli/new/new.py @@ -0,0 +1,130 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface `new` command.""" + +import os +from enum import Enum +from string import Template +from typing import Dict, Optional + +import typer +from typing_extensions import Annotated + +from ..utils import prompt_options + + +class MlFramework(str, Enum): + """Available frameworks.""" + + PYTORCH = "PyTorch" + TENSORFLOW = "TensorFlow" + + +class TemplateNotFound(Exception): + """Raised when template does not exist.""" + + +def load_template(name: str) -> str: + """Load template from template directory and return as text.""" + tpl_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")) + tpl_file_path = os.path.join(tpl_dir, name) + + if not os.path.isfile(tpl_file_path): + raise TemplateNotFound(f"Template '{name}' not found") + + with open(tpl_file_path, encoding="utf-8") as tpl_file: + return tpl_file.read() + + +def render_template(template: str, data: Dict[str, str]) -> str: + """Render template.""" + tpl_file = load_template(template) + tpl = Template(tpl_file) + result = tpl.substitute(data) + return result + + +def create_file(file_path: str, content: str) -> None: + """Create file including all nessecary directories and write content into file.""" + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "w", encoding="utf-8") as f: + f.write(content) + + +def render_and_create(file_path: str, template: str, context: Dict[str, str]) -> None: + """Render template and write to file.""" + content = render_template(template, context) + create_file(file_path, content) + + +def new( + project_name: Annotated[ + str, + typer.Argument(metavar="project_name", help="The name of the project"), + ], + framework: Annotated[ + Optional[MlFramework], + typer.Option(case_sensitive=False, help="The ML framework to use"), + ] = None, +) -> None: + """Create new Flower project.""" + print(f"Creating Flower project {project_name}...") + + if framework is not None: + framework_str = str(framework.value) + else: + framework_value = prompt_options( + "Please select ML framework by typing in the number", + [mlf.value for mlf in MlFramework], + ) + selected_value = [ + name + for name, value in vars(MlFramework).items() + if value == framework_value + ] + framework_str = selected_value[0] + + # Set project directory path + cwd = os.getcwd() + pnl = project_name.lower() + project_dir = os.path.join(cwd, pnl) + + # List of files to render + files = { + "README.md": { + "template": "app/README.md.tpl", + }, + "requirements.txt": { + "template": f"app/requirements.{framework_str.lower()}.txt.tpl" + }, + "flower.toml": {"template": "app/flower.toml.tpl"}, + f"{pnl}/__init__.py": {"template": "app/code/__init__.py.tpl"}, + f"{pnl}/server.py": { + "template": f"app/code/server.{framework_str.lower()}.py.tpl" + }, + f"{pnl}/client.py": { + "template": f"app/code/client.{framework_str.lower()}.py.tpl" + }, + } + context = {"project_name": project_name} + + for file_path, value in files.items(): + render_and_create( + file_path=os.path.join(project_dir, file_path), + template=value["template"], + context=context, + ) + + print("Project creation successful.") diff --git a/src/py/flwr/cli/new/new_test.py b/src/py/flwr/cli/new/new_test.py new file mode 100644 index 000000000000..39717bc67ab3 --- /dev/null +++ b/src/py/flwr/cli/new/new_test.py @@ -0,0 +1,93 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Test for Flower command line interface `new` command.""" + +import os + +from .new import MlFramework, create_file, load_template, new, render_template + + +def test_load_template() -> None: + """Test if load_template returns a string.""" + # Prepare + filename = "app/README.md.tpl" + + # Execute + text = load_template(filename) + + # Assert + assert isinstance(text, str) + + +def test_render_template() -> None: + """Test if a string is correctly substituted.""" + # Prepare + filename = "app/README.md.tpl" + data = {"project_name": "FedGPT"} + + # Execute + result = render_template(filename, data) + + # Assert + assert "# FedGPT" in result + + +def test_create_file(tmp_path: str) -> None: + """Test if file with content is created.""" + # Prepare + file_path = os.path.join(tmp_path, "test.txt") + content = "Foobar" + + # Execute + create_file(file_path, content) + + # Assert + with open(file_path, encoding="utf-8") as f: + text = f.read() + + assert text == "Foobar" + + +def test_new(tmp_path: str) -> None: + """Test if project is created for framework.""" + # Prepare + project_name = "FedGPT" + framework = MlFramework.PYTORCH + expected_files_top_level = { + "requirements.txt", + "fedgpt", + "README.md", + "flower.toml", + } + expected_files_module = { + "__init__.py", + "server.py", + "client.py", + } + + # Change into the temprorary directory + os.chdir(tmp_path) + + # Execute + new(project_name=project_name, framework=framework) + + # Assert + file_list = os.listdir(os.path.join(tmp_path, project_name.lower())) + assert set(file_list) == expected_files_top_level + + file_list = os.listdir( + os.path.join(tmp_path, project_name.lower(), project_name.lower()) + ) + assert set(file_list) == expected_files_module diff --git a/src/py/flwr/cli/new/templates/__init__.py b/src/py/flwr/cli/new/templates/__init__.py new file mode 100644 index 000000000000..7a951c2da1a2 --- /dev/null +++ b/src/py/flwr/cli/new/templates/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower CLI `new` command templates.""" diff --git a/src/py/flwr/cli/new/templates/app/README.md.tpl b/src/py/flwr/cli/new/templates/app/README.md.tpl new file mode 100644 index 000000000000..7904fa8d3a3c --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/README.md.tpl @@ -0,0 +1,33 @@ +# $project_name + +## Install dependencies + +```bash +pip install -r requirements.txt +``` + +## Start the SuperLink + +```bash +flower-superlink --insecure +``` + +## Start the long-running Flower client + +In a new terminal window, start the first long-running Flower client: + +```bash +flower-client-app client:app --insecure +``` + +In yet another new terminal window, start the second long-running Flower client: + +```bash +flower-client-app client:app --insecure +``` + +## Start the ServerApp + +```bash +flower-server-app server:app --insecure +``` diff --git a/src/py/flwr/cli/new/templates/app/__init__.py b/src/py/flwr/cli/new/templates/app/__init__.py new file mode 100644 index 000000000000..617628fc9138 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower CLI `new` command app templates.""" diff --git a/src/py/flwr/cli/new/templates/app/code/__init__.py b/src/py/flwr/cli/new/templates/app/code/__init__.py new file mode 100644 index 000000000000..7f1a0e9f4fa2 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower CLI `new` command app / code templates.""" diff --git a/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl b/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl new file mode 100644 index 000000000000..57998c81efb8 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl @@ -0,0 +1 @@ +"""$project_name.""" diff --git a/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl b/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl new file mode 100644 index 000000000000..006d00f75e40 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl @@ -0,0 +1 @@ +"""$project_name: A Flower / PyTorch app.""" diff --git a/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl b/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl new file mode 100644 index 000000000000..cc00f8ff0b8c --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl @@ -0,0 +1 @@ +"""$project_name: A Flower / TensorFlow app.""" diff --git a/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl b/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl new file mode 100644 index 000000000000..006d00f75e40 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl @@ -0,0 +1 @@ +"""$project_name: A Flower / PyTorch app.""" diff --git a/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl b/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl new file mode 100644 index 000000000000..cc00f8ff0b8c --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl @@ -0,0 +1 @@ +"""$project_name: A Flower / TensorFlow app.""" diff --git a/src/py/flwr/cli/new/templates/app/flower.toml.tpl b/src/py/flwr/cli/new/templates/app/flower.toml.tpl new file mode 100644 index 000000000000..4dd7117bc3a3 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/flower.toml.tpl @@ -0,0 +1,10 @@ +[flower] +name = "$project_name" +version = "1.0.0" +description = "" +license = "Apache-2.0" +authors = ["The Flower Authors "] + +[components] +serverapp = "$project_name.server:app" +clientapp = "$project_name.client:app" diff --git a/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl b/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl new file mode 100644 index 000000000000..d9426e0b62c0 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl @@ -0,0 +1,4 @@ +flwr>=1.8, <2.0 +flwr-datasets[vision]>=0.0.2, <1.0.0 +torch==1.13.1 +torchvision==0.14.1 diff --git a/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl b/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl new file mode 100644 index 000000000000..4fe7bfdc1e89 --- /dev/null +++ b/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl @@ -0,0 +1,4 @@ +flwr>=1.8, <2.0 +flwr-datasets[vision]>=0.0.2, <1.0.0 +tensorflow-macos>=2.9.1, != 2.11.1 ; sys_platform == "darwin" and platform_machine == "arm64" +tensorflow-cpu>=2.9.1, != 2.11.1 ; platform_machine == "x86_64" diff --git a/src/py/flwr/cli/utils.py b/src/py/flwr/cli/utils.py new file mode 100644 index 000000000000..d61189ffc4e3 --- /dev/null +++ b/src/py/flwr/cli/utils.py @@ -0,0 +1,54 @@ +# Copyright 2024 Flower Labs GmbH. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Flower command line interface utils.""" + +from typing import List + +import typer + + +def prompt_options(text: str, options: List[str]) -> str: + """Ask user to select one of the given options and return the selected item.""" + # Turn options into a list with index as in " [ 0] quickstart-pytorch" + options_formatted = [ + " [ " + + typer.style(index, fg=typer.colors.GREEN, bold=True) + + "]" + + f" {typer.style(name, fg=typer.colors.WHITE, bold=True)}" + for index, name in enumerate(options) + ] + + while True: + index = typer.prompt( + "\n" + + typer.style(f"💬 {text}", fg=typer.colors.MAGENTA, bold=True) + + "\n\n" + + "\n".join(options_formatted) + + "\n\n\n" + ) + try: + options[int(index)] # pylint: disable=expression-not-assigned + break + except IndexError: + print(typer.style("❌ Index out of range", fg=typer.colors.RED, bold=True)) + continue + except ValueError: + print( + typer.style("❌ Please choose a number", fg=typer.colors.RED, bold=True) + ) + continue + + result = options[int(index)] + return result From 7056c7eccff6aa69001ff1a692e88ceb887cf7d9 Mon Sep 17 00:00:00 2001 From: Robert Steiner Date: Tue, 20 Feb 2024 13:49:09 +0100 Subject: [PATCH 2/2] pin virtualenv version to 20.21.0 in baselines (#2981) --- baselines/dasha/pyproject.toml | 1 + baselines/depthfl/pyproject.toml | 4 ++-- baselines/fedavgm/pyproject.toml | 3 ++- baselines/fedmeta/pyproject.toml | 2 +- baselines/fedmlb/pyproject.toml | 1 + baselines/fedper/pyproject.toml | 2 +- baselines/fedprox/pyproject.toml | 1 + baselines/fedwav2vec2/pyproject.toml | 1 + baselines/fjord/pyproject.toml | 3 +-- baselines/moon/pyproject.toml | 1 + baselines/niid_bench/pyproject.toml | 1 + baselines/tamuna/pyproject.toml | 1 + 12 files changed, 14 insertions(+), 7 deletions(-) diff --git a/baselines/dasha/pyproject.toml b/baselines/dasha/pyproject.toml index 3ef24e4b985a..6fa6eb028b51 100644 --- a/baselines/dasha/pyproject.toml +++ b/baselines/dasha/pyproject.toml @@ -60,6 +60,7 @@ pytest-watch = "==4.2.0" types-requests = "==2.27.7" py-spy = "==0.3.14" ruff = "==0.0.272" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/depthfl/pyproject.toml b/baselines/depthfl/pyproject.toml index 2f928c2d3553..bd223ba78341 100644 --- a/baselines/depthfl/pyproject.toml +++ b/baselines/depthfl/pyproject.toml @@ -37,14 +37,13 @@ classifiers = [ ] [tool.poetry.dependencies] -python = ">=3.10.0, <3.11.0" +python = ">=3.10.0, <3.11.0" flwr = { extras = ["simulation"], version = "1.5.0" } hydra-core = "1.3.2" # don't change this matplotlib = "3.7.1" torch = { url = "https://download.pytorch.org/whl/cu116/torch-1.13.1%2Bcu116-cp310-cp310-linux_x86_64.whl"} torchvision = { url = "https://download.pytorch.org/whl/cu116/torchvision-0.14.1%2Bcu116-cp310-cp310-linux_x86_64.whl"} - [tool.poetry.dev-dependencies] isort = "==5.11.5" black = "==23.1.0" @@ -56,6 +55,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedavgm/pyproject.toml b/baselines/fedavgm/pyproject.toml index cfd55a5b1fba..22a5f3a53847 100644 --- a/baselines/fedavgm/pyproject.toml +++ b/baselines/fedavgm/pyproject.toml @@ -3,7 +3,7 @@ requires = ["poetry-core>=1.4.0"] build-backend = "poetry.masonry.api" [tool.poetry] -name = "fedavgm" +name = "fedavgm" version = "1.0.0" description = "FedAvgM: Measuring the effects of non-identical data distribution for federated visual classification" license = "Apache-2.0" @@ -56,6 +56,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedmeta/pyproject.toml b/baselines/fedmeta/pyproject.toml index cbaa9bb5d110..8f6bbe3f7fa1 100644 --- a/baselines/fedmeta/pyproject.toml +++ b/baselines/fedmeta/pyproject.toml @@ -46,7 +46,6 @@ torch = { url = "https://download.pytorch.org/whl/cu117/torch-2.0.1%2Bcu117-cp31 torchvision = { url = "https://download.pytorch.org/whl/cu117/torchvision-0.15.2%2Bcu117-cp310-cp310-linux_x86_64.whl"} pillow = "9.5.0" # needed <10.0.0 for LEAF repo scripts - [tool.poetry.dev-dependencies] isort = "==5.11.5" black = "==23.1.0" @@ -58,6 +57,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedmlb/pyproject.toml b/baselines/fedmlb/pyproject.toml index 005803e1891e..c76b2b1548ce 100644 --- a/baselines/fedmlb/pyproject.toml +++ b/baselines/fedmlb/pyproject.toml @@ -55,6 +55,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedper/pyproject.toml b/baselines/fedper/pyproject.toml index efcdf25eface..04aef92a8c06 100644 --- a/baselines/fedper/pyproject.toml +++ b/baselines/fedper/pyproject.toml @@ -46,7 +46,6 @@ tqdm = "^4.66.1" torch = { url = "https://download.pytorch.org/whl/cu117/torch-2.0.1%2Bcu117-cp310-cp310-linux_x86_64.whl"} torchvision = { url = "https://download.pytorch.org/whl/cu117/torchvision-0.15.2%2Bcu117-cp310-cp310-linux_x86_64.whl"} - [tool.poetry.dev-dependencies] isort = "==5.11.5" black = "==23.1.0" @@ -58,6 +57,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedprox/pyproject.toml b/baselines/fedprox/pyproject.toml index ee127ac19fe0..a8a3513d8ddf 100644 --- a/baselines/fedprox/pyproject.toml +++ b/baselines/fedprox/pyproject.toml @@ -57,6 +57,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fedwav2vec2/pyproject.toml b/baselines/fedwav2vec2/pyproject.toml index 1e7dbf55154b..87cfb44e0a5a 100644 --- a/baselines/fedwav2vec2/pyproject.toml +++ b/baselines/fedwav2vec2/pyproject.toml @@ -57,6 +57,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/fjord/pyproject.toml b/baselines/fjord/pyproject.toml index d8a9ae307d7c..6d7466029263 100644 --- a/baselines/fjord/pyproject.toml +++ b/baselines/fjord/pyproject.toml @@ -47,8 +47,6 @@ tqdm = "4.65.0" torch = { url = "https://download.pytorch.org/whl/cu117/torch-2.0.1%2Bcu117-cp310-cp310-linux_x86_64.whl"} torchvision = { url = "https://download.pytorch.org/whl/cu117/torchvision-0.15.2%2Bcu117-cp310-cp310-linux_x86_64.whl"} - - [tool.poetry.dev-dependencies] isort = "==5.11.5" black = "==23.1.0" @@ -60,6 +58,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/moon/pyproject.toml b/baselines/moon/pyproject.toml index e9f826abb2ea..b385cd90300c 100644 --- a/baselines/moon/pyproject.toml +++ b/baselines/moon/pyproject.toml @@ -56,6 +56,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/niid_bench/pyproject.toml b/baselines/niid_bench/pyproject.toml index adb001e031ff..6a7086806e40 100644 --- a/baselines/niid_bench/pyproject.toml +++ b/baselines/niid_bench/pyproject.toml @@ -55,6 +55,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88 diff --git a/baselines/tamuna/pyproject.toml b/baselines/tamuna/pyproject.toml index fedcde9eb1c2..d004cfbd6f90 100644 --- a/baselines/tamuna/pyproject.toml +++ b/baselines/tamuna/pyproject.toml @@ -56,6 +56,7 @@ pytest = "==6.2.4" pytest-watch = "==4.2.0" ruff = "==0.0.272" types-requests = "==2.27.7" +virtualenv = "==20.21.0" [tool.isort] line_length = 88