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

docs(examples) Add table and improve design #3688

Merged
merged 70 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
75b8669
docs(examples:skip) Improve example docs generation script
charlesbvll Jun 25, 2024
509e2e3
Test script
charlesbvll Jun 25, 2024
2b9fc1d
fix script
charlesbvll Jun 25, 2024
07a4039
Add initial metadata
charlesbvll Jun 25, 2024
9430011
Use metadata
charlesbvll Jun 25, 2024
ee0394b
Fix script
charlesbvll Jun 25, 2024
ee01e6b
Update metadata
charlesbvll Jun 25, 2024
7dea640
Update metadata
charlesbvll Jun 25, 2024
35c98b7
Update metadata
charlesbvll Jun 25, 2024
b885819
Remove index from history
charlesbvll Jun 26, 2024
983d086
Update some metadata
charlesbvll Jun 26, 2024
15bd6d6
Update metadata
charlesbvll Jun 26, 2024
b85d117
Update metadata
charlesbvll Jun 26, 2024
2769eec
Update metadata
charlesbvll Jun 26, 2024
1606179
Update metatdata
charlesbvll Jun 26, 2024
c5c7d29
Remove URL
charlesbvll Jun 26, 2024
efcd732
Remove URL handling
charlesbvll Jun 26, 2024
af17161
Improve format and add dscription to table
charlesbvll Jun 28, 2024
0baefdc
Separate tables
charlesbvll Jun 28, 2024
5b0cda8
Capitalize Cp
charlesbvll Jun 28, 2024
acc5bf2
Add Python script
charlesbvll Jun 28, 2024
301d9d4
Update metadata
charlesbvll Jun 28, 2024
0db320e
Update metadata
charlesbvll Jun 28, 2024
c4e2263
Try markdown format
charlesbvll Jun 28, 2024
f4db217
Test with quotes
charlesbvll Jun 28, 2024
3a073a6
Remove quotes
charlesbvll Jun 28, 2024
2f59185
Update MNIST
charlesbvll Jun 28, 2024
78b7ca3
Try quotes markdown
charlesbvll Jun 28, 2024
72d9946
Try simple string
charlesbvll Jun 28, 2024
9020e9e
use pipe
charlesbvll Jun 28, 2024
a5266b8
Fix MNIST metadata format
charlesbvll Jun 28, 2024
919798f
Update rest of metadata
charlesbvll Jun 28, 2024
0eecd2a
Fix script
charlesbvll Jun 28, 2024
ccf76a0
Update Cifar metadata
charlesbvll Jun 28, 2024
0c0a198
Use HF for MNIST link
charlesbvll Jun 28, 2024
9e41df7
Remove quotes
charlesbvll Jun 28, 2024
21f02e2
Update iris and MedNist
charlesbvll Jun 28, 2024
319bc11
Update metadata
charlesbvll Jun 28, 2024
8a4b26b
Update metadata
charlesbvll Jun 28, 2024
d749720
Support lists of tags
charlesbvll Jun 28, 2024
24be99c
Update metadata
charlesbvll Jun 28, 2024
9bcf90f
Update scikit-learn
charlesbvll Jun 28, 2024
56005ba
Update torchvision metadata
charlesbvll Jun 28, 2024
2b79e98
Update torch metadata
charlesbvll Jun 28, 2024
207c373
Add link to xgboost
charlesbvll Jun 28, 2024
604fe0b
Update metadata
charlesbvll Jun 28, 2024
81e7b12
Add building to script
charlesbvll Jun 28, 2024
a169a59
Add keras link
charlesbvll Jun 28, 2024
bdd2ba9
Update metadata
charlesbvll Jun 28, 2024
4d593ce
Add metadata
charlesbvll Jun 28, 2024
5ac931a
Shorten mods
charlesbvll Jun 28, 2024
105c4e9
Remove locale
charlesbvll Jun 28, 2024
dd29d27
Update metadata
charlesbvll Jun 28, 2024
91f1e17
Merge branch 'main' into improve-example-docs-script
charlesbvll Jun 28, 2024
d4dfb7a
Merge branch 'main' into improve-example-docs-script
charlesbvll Jun 30, 2024
3f5f35a
Format README files and update script
charlesbvll Jun 30, 2024
1b8f436
Update build-docs script
charlesbvll Jun 30, 2024
6f4dd4e
Use numbers
charlesbvll Jun 30, 2024
b2fd515
Remove deprecated script
charlesbvll Jun 30, 2024
dd55736
Add copyright notice and reformat
charlesbvll Jun 30, 2024
3427e22
Add error handling
charlesbvll Jun 30, 2024
1206087
Allow no dataset or framework
charlesbvll Jun 30, 2024
9c471b7
Update examples/fl-dp-sa/README.md
charlesbvll Jun 30, 2024
c40f440
Update examples/fl-tabular/README.md
charlesbvll Jun 30, 2024
d69dae4
Update examples/flower-via-docker-compose/README.md
charlesbvll Jun 30, 2024
e4b316f
Update examples/llm-flowertune/README.md
charlesbvll Jun 30, 2024
d30ffcd
Update examples/embedded-devices/README.md
charlesbvll Jun 30, 2024
542f0a4
Merge branch 'main' into improve-example-docs-script
charlesbvll Jun 30, 2024
c91408d
Merge branch 'main' into improve-example-docs-script
danieljanes Jul 1, 2024
5fad5a8
Update dev/build-example-docs.py
danieljanes Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions dev/build-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ cd $ROOT
./dev/build-baseline-docs.sh

cd $ROOT
./dev/update-examples.sh
cd examples/doc
make docs
python dev/build-example-docs.py

cd $ROOT
./datasets/dev/build-flwr-datasets-docs.sh
Expand Down
236 changes: 236 additions & 0 deletions dev/build-example-docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# 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.
# ==============================================================================
"""Build the Flower Example docs."""

import os
import shutil
import re
import subprocess
from pathlib import Path

ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
INDEX = os.path.join(ROOT, "examples", "doc", "source", "index.rst")

initial_text = """
Flower Examples Documentation
-----------------------------

Welcome to Flower Examples' documentation. `Flower <https://flower.ai>`_ is
a friendly federated learning framework.

Join the Flower Community
-------------------------

The Flower Community is growing quickly - we're a friendly group of researchers,
engineers, students, professionals, academics, and other enthusiasts.

.. button-link:: https://flower.ai/join-slack
:color: primary
:shadow:

Join us on Slack

Quickstart Examples
-------------------

Flower Quickstart Examples are a collection of demo projects that show how you
can use Flower in combination with other existing frameworks or technologies.

"""

table_headers = (
"\n.. list-table::\n :widths: 50 15 15 15\n "
":header-rows: 1\n\n * - Title\n - Framework\n - Dataset\n - Tags\n\n"
)

categories = {
"quickstart": {"table": table_headers, "list": ""},
"advanced": {"table": table_headers, "list": ""},
"other": {"table": table_headers, "list": ""},
}


def _convert_to_link(search_result):
if "|" in search_result:
if "," in search_result:
result = ""
for part in search_result.split(","):
result += f"{_convert_to_link(part)}, "
return result[:-2]

name, url = search_result.replace('"', "").split("|")
return f"`{name.strip()} <{url.strip()}>`_"

return search_result


def _read_metadata(example):
with open(os.path.join(example, "README.md")) as f:
content = f.read()

metadata_match = re.search(r"^---(.*?)^---", content, re.DOTALL | re.MULTILINE)
if not metadata_match:
raise ValueError("Metadata block not found")
metadata = metadata_match.group(1)

title_match = re.search(r"^title:\s*(.+)$", metadata, re.MULTILINE)
if not title_match:
raise ValueError("Title not found in metadata")
title = title_match.group(1).strip()

labels_match = re.search(r"^labels:\s*\[(.+?)\]$", metadata, re.MULTILINE)
if not labels_match:
raise ValueError("Labels not found in metadata")
labels = labels_match.group(1).strip()

dataset_match = re.search(
r"^dataset:\s*\[(.*?)\]$", metadata, re.DOTALL | re.MULTILINE
)
if not dataset_match:
raise ValueError("Dataset not found in metadata")
dataset = dataset_match.group(1).strip()

framework_match = re.search(
r"^framework:\s*\[(.*?|)\]$", metadata, re.DOTALL | re.MULTILINE
)
if not framework_match:
raise ValueError("Framework not found in metadata")
framework = framework_match.group(1).strip()

dataset = _convert_to_link(re.sub(r"\s+", " ", dataset).strip())
framework = _convert_to_link(re.sub(r"\s+", " ", framework).strip())
return title, labels, dataset, framework


def _add_table_entry(example, label, table_var):
title, labels, dataset, framework = _read_metadata(example)
example_name = Path(example).stem
table_entry = (
f" * - `{title} <{example_name}.html>`_ \n "
f"- {framework} \n - {dataset} \n - {labels}\n\n"
)
if label in labels:
categories[table_var]["table"] += table_entry
categories[table_var]["list"] += f" {example_name}\n"
return True
return False


def _copy_markdown_files(example):
for file in os.listdir(example):
if file.endswith(".md"):
src = os.path.join(example, file)
dest = os.path.join(
ROOT, "examples", "doc", "source", os.path.basename(example) + ".md"
)
shutil.copyfile(src, dest)


def _add_gh_button(example):
gh_text = f'[<img src="_static/view-gh.png" alt="View on GitHub" width="200"/>](https://github.com/adap/flower/blob/main/examples/{example})'
readme_file = os.path.join(ROOT, "examples", "doc", "source", example + ".md")
with open(readme_file, "r+") as f:
content = f.read()
if gh_text not in content:
content = re.sub(
r"(^# .+$)", rf"\1\n\n{gh_text}", content, count=1, flags=re.MULTILINE
)
f.seek(0)
f.write(content)
f.truncate()


def _copy_images(example):
static_dir = os.path.join(example, "_static")
dest_dir = os.path.join(ROOT, "examples", "doc", "source", "_static")
if os.path.isdir(static_dir):
for file in os.listdir(static_dir):
if file.endswith((".jpg", ".png", ".jpeg")):
shutil.copyfile(
os.path.join(static_dir, file), os.path.join(dest_dir, file)
)


def _add_all_entries(index_file):
examples_dir = os.path.join(ROOT, "examples")
for example in sorted(os.listdir(examples_dir)):
example_path = os.path.join(examples_dir, example)
if os.path.isdir(example_path) and example != "doc":
_copy_markdown_files(example_path)
_add_gh_button(example)
_copy_images(example)


def _main():
if os.path.exists(INDEX):
os.remove(INDEX)

with open(INDEX, "w") as index_file:
index_file.write(initial_text)

examples_dir = os.path.join(ROOT, "examples")
for example in sorted(os.listdir(examples_dir)):
example_path = os.path.join(examples_dir, example)
if os.path.isdir(example_path) and example != "doc":
_copy_markdown_files(example_path)
_add_gh_button(example)
_copy_images(example_path)
if not _add_table_entry(example_path, "quickstart", "quickstart"):
if not _add_table_entry(example_path, "comprehensive", "comprehensive"):
if not _add_table_entry(example_path, "advanced", "advanced"):
_add_table_entry(example_path, "", "other")

with open(INDEX, "a") as index_file:
index_file.write(categories["quickstart"]["table"])

index_file.write("\nAdvanced Examples\n-----------------\n")
index_file.write(
"Advanced Examples are mostly for users that are both familiar with "
"Federated Learning but also somewhat familiar with Flower's main "
"features.\n"
)
index_file.write(categories["advanced"]["table"])

index_file.write("\nOther Examples\n--------------\n")
index_file.write(
"Flower Examples are a collection of example projects written with "
"Flower that explore different domains and features. You can check "
"which examples already exist and/or contribute your own example.\n"
Copy link
Contributor

Choose a reason for hiding this comment

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

should we add a link to the "contribute your own example" text pointing to our contributors guide?

)
index_file.write(categories["other"]["table"])

_add_all_entries(index_file)

index_file.write(
"\n.. toctree::\n :maxdepth: 1\n :caption: Quickstart\n :hidden:\n\n"
)
index_file.write(categories["quickstart"]["list"])

index_file.write(
"\n.. toctree::\n :maxdepth: 1\n :caption: Advanced\n :hidden:\n\n"
)
index_file.write(categories["advanced"]["list"])

index_file.write(
"\n.. toctree::\n :maxdepth: 1\n :caption: Others\n :hidden:\n\n"
)
index_file.write(categories["other"]["list"])

index_file.write("\n")


if __name__ == "__main__":
_main()
subprocess.call(f"cd {ROOT}/examples/doc && make html", shell=True)
91 changes: 0 additions & 91 deletions dev/update-examples.sh

This file was deleted.

7 changes: 7 additions & 0 deletions examples/advanced-pytorch/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
title: Advanced Flower Example using PyTorch
labels: [advanced, vision, fds]
dataset: [CIFAR-10 | https://huggingface.co/datasets/uoft-cs/cifar10]
framework: [torch | https://pytorch.org/, torchvision | https://pytorch.org/vision/stable/index.html]
---

# Advanced Flower Example (PyTorch)

This example demonstrates an advanced federated learning setup using Flower with PyTorch. This example uses [Flower Datasets](https://flower.ai/docs/datasets/) and it differs from the quickstart example in the following ways:
Expand Down
7 changes: 7 additions & 0 deletions examples/advanced-tensorflow/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
title: Advanced Flower Example using TensorFlow/Keras
labels: [advanced, vision, fds]
dataset: [CIFAR-10 | https://huggingface.co/datasets/uoft-cs/cifar10]
framework: [tensorflow | https://www.tensorflow.org/, Keras | https://keras.io/]
---

# Advanced Flower Example (TensorFlow/Keras)

This example demonstrates an advanced federated learning setup using Flower with TensorFlow/Keras. This example uses [Flower Datasets](https://flower.ai/docs/datasets/) and it differs from the quickstart example in the following ways:
Expand Down
8 changes: 8 additions & 0 deletions examples/android-kotlin/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
title: Flower Android Example using Kotlin and TF Lite
labels: [basic, vision, fds]
dataset: [CIFAR-10 | https://huggingface.co/datasets/uoft-cs/cifar10]
framework: [Android | https://www.android.com/, Kotlin | https://kotlinlang.org/,
TensorFlowLite | https://www.tensorflow.org/lite]
---

# Flower Android Client Example with Kotlin and TensorFlow Lite 2022

This example is similar to the Flower Android Example in Java:
Expand Down
8 changes: 8 additions & 0 deletions examples/android/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
title: Flower Android Example using Java and TF Lite
labels: [basic, vision, fds]
dataset: [CIFAR-10 | https://huggingface.co/datasets/uoft-cs/cifar10]
framework: [Android | https://www.android.com/, Java | https://www.java.com/, TensorFlowLite
| https://www.tensorflow.org/lite]
---

# Flower Android Example (TensorFlowLite)

This example demonstrates a federated learning setup with Android clients in a background thread. The training on Android is done on a CIFAR10 dataset using TensorFlow Lite. The setup is as follows:
Expand Down
7 changes: 7 additions & 0 deletions examples/app-pytorch/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
---
title: Example Flower App using PyTorch
labels: [basic, vision, fds]
dataset: [CIFAR-10 | https://huggingface.co/datasets/uoft-cs/cifar10]
framework: [torch | https://pytorch.org/, torchvision | https://pytorch.org/vision/stable/index.html]
---

# Flower App (PyTorch) 🧪

> 🧪 = This example covers experimental features that might change in future versions of Flower
Expand Down
Loading