From dc70b6511c65adbd7cf562a715ae3318d9d39ad7 Mon Sep 17 00:00:00 2001 From: Mansy Date: Fri, 1 Jul 2022 22:28:44 +0200 Subject: [PATCH] Add CI for python lightning app Python unit tests (#13491) * Update lightning_app src * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update lightning app tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add CI * update tests * requirements * fix version tests * todo * fix tests * fix tests * fix tests * fix tests * fix formatting Co-authored-by: mansy Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: awaelchli --- .github/workflows/ci-app_block.yml | 8 - .github/workflows/ci-app_tests.yml | 140 ++ src/lightning_app/__init__.py | 2 +- src/lightning_app/cli/app-template/.gitignore | 8 +- .../cli/app-template/placeholdername/app.py | 6 +- .../components/component_a/component_a.py | 4 +- .../components/component_b/component_a.py | 4 +- .../tests/test_placeholdername_app.py | 2 +- src/lightning_app/cli/cmd_init.py | 2 +- src/lightning_app/cli/cmd_install.py | 29 +- .../.github/workflows/ci-testing.yml | 2 +- .../cli/component-template/.gitignore | 8 +- .../cli/component-template/README.md | 8 +- .../cli/component-template/app.py | 6 +- .../placeholdername/component.py | 4 +- src/lightning_app/cli/lightning_cli.py | 1 + src/lightning_app/cli/pl-app-template/app.py | 8 +- .../cli/pl-app-template/core/callbacks.py | 2 +- .../core/components/logger/tensorboard.py | 4 +- .../components/logger/weights_and_biases.py | 2 +- .../components/script_runner/script_runner.py | 15 +- .../tests/core/test_callbacks.py | 2 +- .../cli/react-ui-template/README.md | 8 +- .../cli/react-ui-template/example_app.py | 11 +- .../cli/react-ui-template/ui/package.json | 2 +- .../cli/react-ui-template/ui/yarn.lock | 1138 +++++++++++++++++ src/lightning_app/components/python/popen.py | 4 +- src/lightning_app/components/python/tracer.py | 34 +- src/lightning_app/components/serve/gradio.py | 2 +- src/lightning_app/core/app.py | 25 +- src/lightning_app/core/flow.py | 89 +- src/lightning_app/core/work.py | 30 +- src/lightning_app/testing/helpers.py | 2 +- src/lightning_app/testing/testing.py | 14 +- src/lightning_app/utilities/app_helpers.py | 2 +- src/lightning_app/utilities/network.py | 2 +- .../utilities/packaging/build_config.py | 43 +- .../utilities/packaging/cloud_compute.py | 4 +- .../utilities/packaging/lightning_utils.py | 65 +- tests/tests_app/cli/test_cmd_react_ui_init.py | 2 +- .../packaging/test_lightning_utils.py | 4 +- tests/tests_app/utilities/test_git.py | 2 +- 42 files changed, 1599 insertions(+), 151 deletions(-) create mode 100644 .github/workflows/ci-app_tests.yml create mode 100644 src/lightning_app/cli/react-ui-template/ui/yarn.lock diff --git a/.github/workflows/ci-app_block.yml b/.github/workflows/ci-app_block.yml index 5eef31cb8c..92b928a68d 100644 --- a/.github/workflows/ci-app_block.yml +++ b/.github/workflows/ci-app_block.yml @@ -19,18 +19,10 @@ jobs: echo "$file" done - - name: Block edits in src/lightning_app - if: contains(steps.changed-files.outputs.all_changed_and_modified_files, 'src/lightning_app') - run: exit 1 - - name: Block edits in docs/source-app if: contains(steps.changed-files.outputs.all_changed_and_modified_files, 'docs/source-app') run: exit 1 - - name: Block edits in tests/tests_app - if: contains(steps.changed-files.outputs.all_changed_and_modified_files, 'tests/tests_app') - run: exit 1 - - name: Block edits in examples/app if: contains(steps.changed-files.outputs.all_changed_and_modified_files, 'examples/app_') run: exit 1 diff --git a/.github/workflows/ci-app_tests.yml b/.github/workflows/ci-app_tests.yml new file mode 100644 index 0000000000..0c87c3f4c2 --- /dev/null +++ b/.github/workflows/ci-app_tests.yml @@ -0,0 +1,140 @@ +name: CI App Tests + +# see: https://help.github.com/en/actions/reference/events-that-trigger-workflows +on: # Trigger the workflow on push or pull request, but only for the master branch + push: + branches: + - "master" + pull_request: + paths: + - "src/lightning_app/**" + - "tests/tests_app/**" + - "requirements/app/**" + - "setup.py" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +jobs: + pytest: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04, macOS-10.15, windows-2019] + python-version: [3.8] + requires: ["oldest", "latest"] + + # Timeout: https://stackoverflow.com/a/59076067/4521646 + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + # TODO: use replace_oldest_ver() instead + - name: Set min. dependencies + if: matrix.requires == 'oldest' + run: | + for fpath in ('requirements/app/base.txt', 'requirements/app/test.txt'): + req = open(fpath).read().replace('>=', '==') + open(fpath, 'w').write(req) + shell: python + + - run: echo "::set-output name=period::$(python -c 'import time ; days = time.time() / 60 / 60 / 24 ; print(int(days / 7))' 2>&1)" + if: matrix.requires == 'latest' + id: times + + # Note: This uses an internal pip API and may not always work + # https://github.com/actions/cache/blob/master/examples.md#multiple-oss-in-a-workflow + - name: Get pip cache + id: pip-cache + run: | + python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)" + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ matrix.requires }}-td${{ steps.times.outputs.period }}-${{ hashFiles('requirements/app/base.txt') }} + restore-keys: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ matrix.requires }}-td${{ steps.times.outputs.period }}- + + - name: Install dependencies + run: | + pip --version + pip install -r requirements/app/devel.txt --quiet --find-links https://download.pytorch.org/whl/cpu/torch_stable.html + pip list + shell: bash + +# - name: Start Redis +# if: runner.os == 'Linux' +# uses: supercharge/redis-github-action@1.4.0 +# with: +# redis-version: 6 +# redis-port: 6379 + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '16' + + - name: Install Yarn + run: npm install -g yarn + + - name: Install Lightning as top-level + run: pip install -e . -r requirements/app/base.txt + shell: bash + + - name: Tests + working-directory: ./tests + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: us-east-1 + PYTEST_ARTIFACT: results-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.requires }}.xml + run: | + coverage run --source lightning_app -m pytest -m "not cloud" tests_app --timeout=300 -vvvv --junitxml=$PYTEST_ARTIFACT --durations=0 + + - name: Upload pytest test results + uses: actions/upload-artifact@v2 + with: + name: unittest-results-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.requires }} + path: tests/results-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.requires }}.xml + if: failure() + + - name: Statistics + if: success() + working-directory: ./tests + run: | + coverage xml -i + coverage report -i + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: tests/coverage.xml + flags: unittests + env_vars: OS,PYTHON + name: codecov-umbrella + fail_ci_if_error: false + +# TODO: figure out why we clone and install quick-start +# - name: Clone Quick Start Example Repo +# uses: actions/checkout@v3 +# # TODO: this needs to be git submodule +# if: matrix.os == 'windows-2019' # because the install doesn't work on windows +# with: +# repository: Lightning-AI/lightning-quick-start +# ref: 'main' +# path: lightning-quick-start +# +# - name: Lightning Install quick-start +# shell: bash +# if: matrix.os != 'windows-2019' # because the install doesn't work on windows +# run: | +# python -m lightning install app lightning/quick-start -y diff --git a/src/lightning_app/__init__.py b/src/lightning_app/__init__.py index b680564bda..07926c2036 100644 --- a/src/lightning_app/__init__.py +++ b/src/lightning_app/__init__.py @@ -37,6 +37,6 @@ if _module_available("lightning_app.components.demo"): from lightning_app.components import demo # noqa: F401 _PACKAGE_ROOT = os.path.dirname(__file__) -_PROJECT_ROOT = os.path.dirname(_PACKAGE_ROOT) +_PROJECT_ROOT = os.path.dirname(os.path.dirname(_PACKAGE_ROOT)) __all__ = ["LightningApp", "LightningFlow", "LightningWork", "BuildConfig", "CloudCompute"] diff --git a/src/lightning_app/cli/app-template/.gitignore b/src/lightning_app/cli/app-template/.gitignore index 1c6df52967..09f455310c 100644 --- a/src/lightning_app/cli/app-template/.gitignore +++ b/src/lightning_app/cli/app-template/.gitignore @@ -58,8 +58,8 @@ coverage.xml # Sphinx documentation docs/_build/ -docs/source/api/ -docs/source/*.md +docs/source-app/api/ +docs/source-app/*.md # PyBuilder target/ @@ -132,9 +132,9 @@ coverage.* # Frontend build artifacts *lightning_app/ui* gradio_cached_examples -/docs/source/api_reference/generated/* +/docs/source-app/api_reference/generated/* examples/my_own_leaderboard/submissions/* -docs/source/api_reference/generated/* +docs/source-app/api_reference/generated/* *.ckpt redis-stable node_modules diff --git a/src/lightning_app/cli/app-template/placeholdername/app.py b/src/lightning_app/cli/app-template/placeholdername/app.py index e667aa172c..a7ce8a3070 100644 --- a/src/lightning_app/cli/app-template/placeholdername/app.py +++ b/src/lightning_app/cli/app-template/placeholdername/app.py @@ -1,9 +1,9 @@ from placeholdername import ComponentA, ComponentB -import lightning_app as la +import lightning as L -class LitApp(la.LightningFlow): +class LitApp(L.LightningFlow): def __init__(self) -> None: super().__init__() self.component_a = ComponentA() @@ -14,4 +14,4 @@ class LitApp(la.LightningFlow): self.component_b.run() -app = la.LightningApp(LitApp()) +app = L.LightningApp(LitApp()) diff --git a/src/lightning_app/cli/app-template/placeholdername/components/component_a/component_a.py b/src/lightning_app/cli/app-template/placeholdername/components/component_a/component_a.py index 446619bfb9..172aaab324 100644 --- a/src/lightning_app/cli/app-template/placeholdername/components/component_a/component_a.py +++ b/src/lightning_app/cli/app-template/placeholdername/components/component_a/component_a.py @@ -1,6 +1,6 @@ -import lightning_app as la +import lightning as L -class ComponentA(la.LightningFlow): +class ComponentA(L.LightningFlow): def run(self): print("hello from component A") diff --git a/src/lightning_app/cli/app-template/placeholdername/components/component_b/component_a.py b/src/lightning_app/cli/app-template/placeholdername/components/component_b/component_a.py index d309ebc7c3..c5537d9565 100644 --- a/src/lightning_app/cli/app-template/placeholdername/components/component_b/component_a.py +++ b/src/lightning_app/cli/app-template/placeholdername/components/component_b/component_a.py @@ -1,6 +1,6 @@ -import lightning_app as la +import lightning as L -class ComponentB(la.LightningFlow): +class ComponentB(L.LightningFlow): def run(self): print("hello from component B") diff --git a/src/lightning_app/cli/app-template/tests/test_placeholdername_app.py b/src/lightning_app/cli/app-template/tests/test_placeholdername_app.py index fffc137db5..da2bca5907 100644 --- a/src/lightning_app/cli/app-template/tests/test_placeholdername_app.py +++ b/src/lightning_app/cli/app-template/tests/test_placeholdername_app.py @@ -10,7 +10,7 @@ import io import os from contextlib import redirect_stdout -from lightning_app.testing.testing import application_testing, LightningTestApp +from lightning.app.testing.testing import application_testing, LightningTestApp class LightningAppTestInt(LightningTestApp): diff --git a/src/lightning_app/cli/cmd_init.py b/src/lightning_app/cli/cmd_init.py index fb80a6fecc..4e239da87c 100644 --- a/src/lightning_app/cli/cmd_init.py +++ b/src/lightning_app/cli/cmd_init.py @@ -124,7 +124,7 @@ def component(component_name): ⚡ Use the component inside an app: ⚡ from {name_for_files} import TemplateComponent - import lightning_app as la + import lightning.app as la class LitApp(la.LightningFlow): def __init__(self) -> None: diff --git a/src/lightning_app/cli/cmd_install.py b/src/lightning_app/cli/cmd_install.py index d7bb0b435a..4fbaefd924 100644 --- a/src/lightning_app/cli/cmd_install.py +++ b/src/lightning_app/cli/cmd_install.py @@ -49,10 +49,12 @@ def gallery_app(name, yes_arg, version_arg, cwd=None, overwrite=False): app_entry = _resolve_resource(registry_url, name=name, version_arg=version_arg, resource_type="app") # give the user the chance to do a manual install - source_url, git_url, folder_name = _show_install_app_prompt(app_entry, app, org, yes_arg, resource_type="app") + source_url, git_url, folder_name, git_sha = _show_install_app_prompt( + app_entry, app, org, yes_arg, resource_type="app" + ) # run installation if requested - _install_app(source_url, git_url, folder_name, cwd=cwd, overwrite=overwrite) + _install_app(source_url, git_url, folder_name, cwd=cwd, overwrite=overwrite, git_sha=git_sha) def non_gallery_app(gh_url, yes_arg, cwd=None, overwrite=False): @@ -161,14 +163,16 @@ def _show_non_gallery_install_component_prompt(gh_url, yes_arg): def _show_install_app_prompt(entry, app, org, yes_arg, resource_type): source_url = entry["sourceUrl"] # This URL is used only to display the repo and extract folder name full_git_url = entry["gitUrl"] # Used to clone the repo (can include tokens for private repos) - git_url = full_git_url.split("#ref=")[0] + git_url_parts = full_git_url.split("#ref=") + git_url = git_url_parts[0] + git_sha = git_url_parts[1] if len(git_url_parts) == 2 else None folder_name = source_url.split("/")[-1] # yes arg does not prompt the user for permission to install anything # automatically creates env and sets up the project if yes_arg: - return source_url, git_url, folder_name + return source_url, git_url, folder_name, git_sha prompt = f""" ⚡ Installing Lightning {resource_type} ⚡ @@ -192,7 +196,7 @@ def _show_install_app_prompt(entry, app, org, yes_arg, resource_type): if not should_install: raise KeyboardInterrupt() - return source_url, git_url, folder_name + return source_url, git_url, folder_name, git_sha except KeyboardInterrupt: repo = entry["sourceUrl"] m = f""" @@ -367,7 +371,9 @@ def _install_with_env(repo_url, folder_name, cwd=None): logger.info(m) -def _install_app(source_url: str, git_url: str, folder_name: str, cwd=None, overwrite: bool = False): +def _install_app( + source_url: str, git_url: str, folder_name: str, cwd=None, overwrite: bool = False, git_sha: str = None +): """Installing lighting app from the `git_url` Args: @@ -381,6 +387,8 @@ def _install_app(source_url: str, git_url: str, folder_name: str, cwd=None, over Working director. If not specified, current working directory is used. overwrite: If true, overwrite the app directory without asking if it already exists + git_sha: + The git_sha for checking out the git repo of the app. """ if not cwd: @@ -412,6 +420,15 @@ def _install_app(source_url: str, git_url: str, folder_name: str, cwd=None, over os.chdir(f"{folder_name}") cwd = os.getcwd() + try: + if git_sha: + subprocess.check_output(["git", "checkout", git_sha], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + if "did not match any" in str(e.output): + raise SystemExit("Looks like the git SHA is not valid or doesn't exist in app repo.") + else: + raise Exception(e) + # activate and install reqs # TODO: remove shell=True... but need to run command in venv logger.info("⚡ RUN: install requirements (pip install -r requirements.txt)") diff --git a/src/lightning_app/cli/component-template/.github/workflows/ci-testing.yml b/src/lightning_app/cli/component-template/.github/workflows/ci-testing.yml index 019693bb73..a15100b3b1 100644 --- a/src/lightning_app/cli/component-template/.github/workflows/ci-testing.yml +++ b/src/lightning_app/cli/component-template/.github/workflows/ci-testing.yml @@ -52,7 +52,7 @@ jobs: - name: Clone Template React UI Repo uses: actions/checkout@v3 with: - repository: PyTorchLightning/lightning + repository: Lightning-AI/lightning token: ${{ secrets.PAT_GHOST }} ref: 'master' path: lightning diff --git a/src/lightning_app/cli/component-template/.gitignore b/src/lightning_app/cli/component-template/.gitignore index 1c6df52967..09f455310c 100644 --- a/src/lightning_app/cli/component-template/.gitignore +++ b/src/lightning_app/cli/component-template/.gitignore @@ -58,8 +58,8 @@ coverage.xml # Sphinx documentation docs/_build/ -docs/source/api/ -docs/source/*.md +docs/source-app/api/ +docs/source-app/*.md # PyBuilder target/ @@ -132,9 +132,9 @@ coverage.* # Frontend build artifacts *lightning_app/ui* gradio_cached_examples -/docs/source/api_reference/generated/* +/docs/source-app/api_reference/generated/* examples/my_own_leaderboard/submissions/* -docs/source/api_reference/generated/* +docs/source-app/api_reference/generated/* *.ckpt redis-stable node_modules diff --git a/src/lightning_app/cli/component-template/README.md b/src/lightning_app/cli/component-template/README.md index 7ec8feb881..16e5911bb8 100644 --- a/src/lightning_app/cli/component-template/README.md +++ b/src/lightning_app/cli/component-template/README.md @@ -8,7 +8,7 @@ lightning init component placeholdername ## To run placeholdername -First, install placeholdername (warning: this app has not been officially approved on the lightning gallery): +First, install placeholdername (warning: this component has not been officially approved on the lightning gallery): ```bash lightning install component https://github.com/theUser/placeholdername @@ -18,10 +18,10 @@ Once the app is installed, use it in an app: ```python from placeholdername import TemplateComponent -import lightning_app as la +import lightning as L -class LitApp(lapp.LightningFlow): +class LitApp(L.LightningFlow): def __init__(self) -> None: super().__init__() self.placeholdername = TemplateComponent() @@ -31,5 +31,5 @@ class LitApp(lapp.LightningFlow): self.placeholdername.run() -app = lapp.LightningApp(LitApp()) +app = L.LightningApp(LitApp()) ``` diff --git a/src/lightning_app/cli/component-template/app.py b/src/lightning_app/cli/component-template/app.py index c413a044bb..49db53e353 100644 --- a/src/lightning_app/cli/component-template/app.py +++ b/src/lightning_app/cli/component-template/app.py @@ -1,9 +1,9 @@ from placeholdername import TemplateComponent -import lightning_app as la +import lightning as L -class LitApp(la.LightningFlow): +class LitApp(L.LightningFlow): def __init__(self) -> None: super().__init__() self.placeholdername = TemplateComponent() @@ -13,4 +13,4 @@ class LitApp(la.LightningFlow): self.placeholdername.run() -app = la.LightningApp(LitApp()) +app = L.LightningApp(LitApp()) diff --git a/src/lightning_app/cli/component-template/placeholdername/component.py b/src/lightning_app/cli/component-template/placeholdername/component.py index 61b36ac356..3b8bc0e2b0 100644 --- a/src/lightning_app/cli/component-template/placeholdername/component.py +++ b/src/lightning_app/cli/component-template/placeholdername/component.py @@ -1,7 +1,7 @@ -import lightning_app as la +import lightning as L -class TemplateComponent(la.LightningWork): +class TemplateComponent(L.LightningWork): def __init__(self) -> None: super().__init__() self.value = 0 diff --git a/src/lightning_app/cli/lightning_cli.py b/src/lightning_app/cli/lightning_cli.py index 1ff0dab330..fb39f743ec 100644 --- a/src/lightning_app/cli/lightning_cli.py +++ b/src/lightning_app/cli/lightning_cli.py @@ -68,6 +68,7 @@ def _run_app( ) env_vars = _format_input_env_variables(env) + os.environ.update(env_vars) def on_before_run(*args): if open_ui and not without_server: diff --git a/src/lightning_app/cli/pl-app-template/app.py b/src/lightning_app/cli/pl-app-template/app.py index 7f3d5965b5..01bc0106f2 100644 --- a/src/lightning_app/cli/pl-app-template/app.py +++ b/src/lightning_app/cli/pl-app-template/app.py @@ -4,10 +4,10 @@ from typing import Dict, List, Optional, Union from core.components import TensorBoard, WeightsAndBiases from core.components.script_runner import ScriptRunner -from lightning_app import LightningApp, LightningFlow -from lightning_app.frontend import StaticWebFrontend -from lightning_app.storage import Path -from lightning_app.utilities.packaging.cloud_compute import CloudCompute +from lightning.app import LightningApp, LightningFlow +from lightning.app.frontend import StaticWebFrontend +from lightning.app.storage import Path +from lightning.app.utilities.packaging.cloud_compute import CloudCompute class ReactUI(LightningFlow): diff --git a/src/lightning_app/cli/pl-app-template/core/callbacks.py b/src/lightning_app/cli/pl-app-template/core/callbacks.py index 93992c552f..de1bb4003f 100644 --- a/src/lightning_app/cli/pl-app-template/core/callbacks.py +++ b/src/lightning_app/cli/pl-app-template/core/callbacks.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Optional, TYPE_CHECKING, Union from core.state import ProgressBarState, TrainerState import pytorch_lightning as pl -from lightning_app.storage import Path +from lightning.app.storage import Path from pytorch_lightning import Callback from pytorch_lightning.callbacks.progress.base import get_standard_metrics from pytorch_lightning.loggers import TensorBoardLogger, WandbLogger diff --git a/src/lightning_app/cli/pl-app-template/core/components/logger/tensorboard.py b/src/lightning_app/cli/pl-app-template/core/components/logger/tensorboard.py index cd7f406dd5..6f5b2eb563 100644 --- a/src/lightning_app/cli/pl-app-template/core/components/logger/tensorboard.py +++ b/src/lightning_app/cli/pl-app-template/core/components/logger/tensorboard.py @@ -2,8 +2,8 @@ import subprocess import time from typing import Dict, List -from lightning_app import BuildConfig, LightningFlow, LightningWork -from lightning_app.storage import Path +from lightning.app import BuildConfig, LightningFlow, LightningWork +from lightning.app.storage import Path class TensorBoard(LightningFlow): diff --git a/src/lightning_app/cli/pl-app-template/core/components/logger/weights_and_biases.py b/src/lightning_app/cli/pl-app-template/core/components/logger/weights_and_biases.py index a3fb0131cb..c0fbbadc7c 100644 --- a/src/lightning_app/cli/pl-app-template/core/components/logger/weights_and_biases.py +++ b/src/lightning_app/cli/pl-app-template/core/components/logger/weights_and_biases.py @@ -1,7 +1,7 @@ import os from typing import Dict, List, Optional, TYPE_CHECKING -from lightning_app import LightningFlow +from lightning.app import LightningFlow if TYPE_CHECKING: import wandb diff --git a/src/lightning_app/cli/pl-app-template/core/components/script_runner/script_runner.py b/src/lightning_app/cli/pl-app-template/core/components/script_runner/script_runner.py index 3eb10dfeee..7cef61a2a5 100644 --- a/src/lightning_app/cli/pl-app-template/core/components/script_runner/script_runner.py +++ b/src/lightning_app/cli/pl-app-template/core/components/script_runner/script_runner.py @@ -1,14 +1,12 @@ -import os import sys import traceback from typing import Any, Dict, List, Optional, Tuple -from pkg_resources import parse_requirements - -from lightning_app.components.python import TracerPythonScript -from lightning_app.storage import Path -from lightning_app.utilities.packaging.build_config import BuildConfig -from lightning_app.utilities.tracer import Tracer +from lightning.app.components.python import TracerPythonScript +from lightning.app.storage import Path +from lightning.app.utilities.packaging.build_config import BuildConfig +from lightning.app.utilities.tracer import Tracer +from lightning_app.utilities.packaging.build_config import load_requirements class ScriptRunner(TracerPythonScript): @@ -76,7 +74,6 @@ class ScriptRunner(TracerPythonScript): ] if Path(root_path, "requirements.txt").exists(): # Requirements from the user's code folder - path_req = os.path.join(root_path, "requirements.txt") - requirements.extend(list(map(str, parse_requirements(open(path_req).readlines())))) + requirements.extend(load_requirements(root_path, file_name="requirements.txt")) return BuildConfig(requirements=requirements) diff --git a/src/lightning_app/cli/pl-app-template/tests/core/test_callbacks.py b/src/lightning_app/cli/pl-app-template/tests/core/test_callbacks.py index ed058d7ce7..d7fb5c1064 100644 --- a/src/lightning_app/cli/pl-app-template/tests/core/test_callbacks.py +++ b/src/lightning_app/cli/pl-app-template/tests/core/test_callbacks.py @@ -5,7 +5,7 @@ import pytest from core.callbacks import PLAppArtifactsTracker, PLAppProgressTracker, PLAppSummary from core.components.script_runner import ScriptRunner -from lightning_app.storage import Path +from lightning.app.storage import Path from pytorch_lightning import LightningModule, Trainer from pytorch_lightning.loggers import TensorBoardLogger diff --git a/src/lightning_app/cli/react-ui-template/README.md b/src/lightning_app/cli/react-ui-template/README.md index a2fdc147de..023fb3babc 100644 --- a/src/lightning_app/cli/react-ui-template/README.md +++ b/src/lightning_app/cli/react-ui-template/README.md @@ -4,7 +4,7 @@ This is a full react template ready to use in a component This UI was automatically generated with: -```bash +```commandline lightning init react-ui ``` @@ -34,12 +34,12 @@ lightning run app react-ui/example_app.py To connect the react UI to your component, simply point the `StaticWebFrontend` to the `dist/` folder generated by yarn after building your react website. ```python -import lightning_app as la +import lightning as L -class YourComponent(lapp.LightningFlow): +class YourComponent(L.LightningFlow): def configure_layout(self): - return lapp.frontend.StaticWebFrontend(Path(__file__).parent / "react-ui/src/dist") + return Lapp.frontend.StaticWebFrontend(Path(__file__).parent / "react-ui/src/dist") ``` ### Set up interactions between React and the component diff --git a/src/lightning_app/cli/react-ui-template/example_app.py b/src/lightning_app/cli/react-ui-template/example_app.py index 735f1782e4..e99f61e38a 100644 --- a/src/lightning_app/cli/react-ui-template/example_app.py +++ b/src/lightning_app/cli/react-ui-template/example_app.py @@ -2,20 +2,21 @@ from pathlib import Path -import lightning_app as la +import lightning as L +from lightning.app import frontend -class YourComponent(la.LightningFlow): +class YourComponent(L.LightningFlow): def __init__(self): super().__init__() self.message_to_print = "Hello World!" self.should_print = False def configure_layout(self): - return la.frontend.StaticWebFrontend(Path(__file__).parent / "ui/dist") + return frontend.StaticWebFrontend(Path(__file__).parent / "ui/dist") -class HelloLitReact(la.LightningFlow): +class HelloLitReact(L.LightningFlow): def __init__(self): super().__init__() self.counter = 0 @@ -30,4 +31,4 @@ class HelloLitReact(la.LightningFlow): return [{"name": "React UI", "content": self.react_ui}] -app = la.LightningApp(HelloLitReact()) +app = L.LightningApp(HelloLitReact()) diff --git a/src/lightning_app/cli/react-ui-template/ui/package.json b/src/lightning_app/cli/react-ui-template/ui/package.json index ef7e7a5850..3245255a47 100644 --- a/src/lightning_app/cli/react-ui-template/ui/package.json +++ b/src/lightning_app/cli/react-ui-template/ui/package.json @@ -10,7 +10,7 @@ "dependencies": { "@emotion/react": "^11.8.2", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.5.0", + "@mui/material": "5.8.5", "axios": "^0.26.1", "lodash": "^4.17.21", "nanoid": "^3.3.1", diff --git a/src/lightning_app/cli/react-ui-template/ui/yarn.lock b/src/lightning_app/cli/react-ui-template/ui/yarn.lock new file mode 100644 index 0000000000..3cba665d27 --- /dev/null +++ b/src/lightning_app/cli/react-ui-template/ui/yarn.lock @@ -0,0 +1,1138 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.6.tgz#8b37d24e88e8e21c499d4328db80577d8882fa53" + integrity sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ== + +"@babel/core@^7.17.10": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.6.tgz#54a107a3c298aee3fe5e1947a6464b9b6faca03d" + integrity sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.6" + "@babel/helper-compilation-targets" "^7.18.6" + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helpers" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.6": + version "7.18.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd" + integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A== + dependencies: + "@babel/types" "^7.18.7" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-compilation-targets@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz#18d35bfb9f83b1293c22c55b3d576c1315b6ed96" + integrity sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg== + dependencies: + "@babel/compat-data" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz#b7eee2b5b9d70602e59d1a6cad7dd24de7ca6cd7" + integrity sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q== + +"@babel/helper-function-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz#8334fecb0afba66e6d87a7e8c6bb7fed79926b83" + integrity sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz#57e3ca669e273d55c3cda55e6ebf552f37f483c8" + integrity sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw== + dependencies: + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz#9448974dd4fb1d80fefe72e8a0af37809cd30d6d" + integrity sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg== + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.6.tgz#4c966140eaa1fcaa3d5a8c09d7db61077d4debfd" + integrity sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.6.tgz#845338edecad65ebffef058d3be851f1d28a63bc" + integrity sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw== + +"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.16.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx-self@^7.16.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7" + integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-source@^7.16.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz#06e9ae8a14d2bc19ce6e3c447d842032a50598fc" + integrity sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.17.3", "@babel/plugin-transform-react-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz#2721e96d31df96e3b7ad48ff446995d26bc028ff" + integrity sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/runtime@^7.13.10", "@babel/runtime@^7.17.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" + integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" + integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + +"@babel/traverse@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.6.tgz#a228562d2f46e89258efa4ddd0416942e2fd671d" + integrity sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.6" + "@babel/helper-function-name" "^7.18.6" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.6" + "@babel/types" "^7.18.6" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.6", "@babel/types@^7.18.7": + version "7.18.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.7.tgz#a4a2c910c15040ea52cdd1ddb1614a65c8041726" + integrity sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@emotion/babel-plugin@^11.7.1": + version "11.9.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz#723b6d394c89fb2ef782229d92ba95a740576e95" + integrity sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + +"@emotion/cache@^11.7.1", "@emotion/cache@^11.9.3": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.9.3.tgz#96638449f6929fd18062cfe04d79b29b44c0d6cb" + integrity sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.1" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + +"@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + +"@emotion/is-prop-valid@^1.1.2", "@emotion/is-prop-valid@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.3.tgz#f0907a416368cf8df9e410117068e20fe87c0a3a" + integrity sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA== + dependencies: + "@emotion/memoize" "^0.7.4" + +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11.8.2": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.3.tgz#f4f4f34444f6654a2e550f5dab4f2d360c101df9" + integrity sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.9.3" + "@emotion/serialize" "^1.0.4" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + +"@emotion/serialize@^1.0.2", "@emotion/serialize@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.4.tgz#ff31fd11bb07999611199c2229e152faadc21a3c" + integrity sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + +"@emotion/sheet@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.1.tgz#015756e2a9a3c7c5f11d8ec22966a8dbfbfac787" + integrity sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA== + +"@emotion/styled@^11.8.1": + version "11.9.3" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.9.3.tgz#47f0c71137fec7c57035bf3659b52fb536792340" + integrity sha512-o3sBNwbtoVz9v7WB1/Y/AmXl69YHmei2mrVnK7JgyBJ//Rst5yqPZCecEJlMlJrFeWHp+ki/54uN265V2pEcXA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/is-prop-valid" "^1.1.3" + "@emotion/serialize" "^1.0.4" + "@emotion/utils" "^1.1.0" + +"@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" + integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== + +"@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz#687cc2bbf243f4e9a868ecf2262318e2658873a1" + integrity sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@mui/base@5.0.0-alpha.86": + version "5.0.0-alpha.86" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.86.tgz#7ac5af939cec7e763c1bf49bf5e30bb9464c4ebf" + integrity sha512-0vi/Nni1mizrgrzKeyksEjw5JVSrgT8Vr2NhxzFtYxqpMgtdSrBvcmcuzBf9kE/ECMPbgpSIcqv0nLbLZUYkOQ== + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/is-prop-valid" "^1.1.2" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + "@popperjs/core" "^2.11.5" + clsx "^1.1.1" + prop-types "^15.8.1" + react-is "^17.0.2" + +"@mui/material@5.8.5": + version "5.8.5" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.8.5.tgz#a1a79fc57b212a9781eb4a53e9995c4a9df04753" + integrity sha512-wngPXlOI9BurLSGlObQM/2L0QFFaIcvJnDK5A+ALxuUyuQnPviVWfC1l/r8rPlxQ4PCbSYpq3gzLlgnLoWcO/g== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/base" "5.0.0-alpha.86" + "@mui/system" "^5.8.5" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.4" + "@types/react-transition-group" "^4.4.4" + clsx "^1.1.1" + csstype "^3.1.0" + prop-types "^15.8.1" + react-is "^17.0.2" + react-transition-group "^4.4.2" + +"@mui/private-theming@^5.8.6": + version "5.8.6" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.8.6.tgz#db2bafeda1699e43e67b3ff4f770d6b7a234501f" + integrity sha512-yHsJk1qU9r/q0DlnxGRJPHyM0Y/nUv8FTNgDTiI9I58GWuVuZqeTUr7JRvPh6ybeP/FLtW5eXEavRK9wxVk4uQ== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/utils" "^5.8.6" + prop-types "^15.8.1" + +"@mui/styled-engine@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.8.0.tgz#89ed42efe7c8749e5a60af035bc5d3a6bea362bf" + integrity sha512-Q3spibB8/EgeMYHc+/o3RRTnAYkSl7ROCLhXJ830W8HZ2/iDiyYp16UcxKPurkXvLhUaILyofPVrP3Su2uKsAw== + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/cache" "^11.7.1" + prop-types "^15.8.1" + +"@mui/system@^5.8.5": + version "5.8.6" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.8.6.tgz#aed7e501c513429dab9cfbbe86da5dcd056c2a0a" + integrity sha512-+a+rD58XltKQHDrrjcuCta2cUBqdnLDUDwnphSLCMFigRl8/uk+R+fdQRlMNRXAOgnMb8ioWIgfjxri5pmTH4A== + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/private-theming" "^5.8.6" + "@mui/styled-engine" "^5.8.0" + "@mui/types" "^7.1.4" + "@mui/utils" "^5.8.6" + clsx "^1.1.1" + csstype "^3.1.0" + prop-types "^15.8.1" + +"@mui/types@^7.1.4": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.4.tgz#4185c05d6df63ec673cda15feab80440abadc764" + integrity sha512-uveM3byMbthO+6tXZ1n2zm0W3uJCQYtwt/v5zV5I77v2v18u0ITkb8xwhsDD2i3V2Kye7SaNR6FFJ6lMuY/WqQ== + +"@mui/utils@^5.8.4", "@mui/utils@^5.8.6": + version "5.8.6" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.8.6.tgz#543de64a64bb9135316ecfd91d75a8740544d79f" + integrity sha512-QM2Sd1xZo2jOt2Vz5Rmro+pi2FLJyiv4+OjxkUwXR3oUM65KSMAMLl/KNYU55s3W3DLRFP5MVwE4FhAbHseHAg== + dependencies: + "@babel/runtime" "^7.17.2" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + prop-types "^15.8.1" + react-is "^17.0.2" + +"@popperjs/core@^2.11.5": + version "2.11.5" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" + integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== + +"@rollup/pluginutils@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d" + integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ== + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" + +"@types/lodash@^4.14.179": + version "4.14.182" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/prop-types@*", "@types/prop-types@^15.7.5": + version "15.7.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" + integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + +"@types/react-dom@^18.0.0": + version "18.0.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.5.tgz#330b2d472c22f796e5531446939eacef8378444a" + integrity sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA== + dependencies: + "@types/react" "*" + +"@types/react-is@^16.7.1 || ^17.0.0": + version "17.0.3" + resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a" + integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw== + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.4": + version "4.4.5" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" + integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.0.1": + version "18.0.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.14.tgz#e016616ffff51dba01b04945610fe3671fdbe06d" + integrity sha512-x4gGuASSiWmo0xjDLpm5mPb52syZHJx02VKbqUKdLmKtAwIh63XClGsiTI1K6DO5q7ox4xAsQrU+Gl3+gGXF9Q== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + +"@vitejs/plugin-react@^1.0.7": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz#2fcf0b6ce9bcdcd4cec5c760c199779d5657ece1" + integrity sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA== + dependencies: + "@babel/core" "^7.17.10" + "@babel/plugin-transform-react-jsx" "^7.17.3" + "@babel/plugin-transform-react-jsx-development" "^7.16.7" + "@babel/plugin-transform-react-jsx-self" "^7.16.7" + "@babel/plugin-transform-react-jsx-source" "^7.16.7" + "@rollup/pluginutils" "^4.2.1" + react-refresh "^0.13.0" + resolve "^1.22.0" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +axios@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + +babel-plugin-macros@^2.6.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +browserslist@^4.20.2: + version "4.21.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.1.tgz#c9b9b0a54c7607e8dc3e01a0d311727188011a00" + integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ== + dependencies: + caniuse-lite "^1.0.30001359" + electron-to-chromium "^1.4.172" + node-releases "^2.0.5" + update-browserslist-db "^1.0.4" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001359: + version "1.0.30001361" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz#ba2adb2527566fb96f3ac7c67698ae7fc495a28d" + integrity sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +convert-source-map@^1.5.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +csstype@^3.0.2, csstype@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" + integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +electron-to-chromium@^1.4.172: + version "1.4.174" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.174.tgz#ffdf57f26dd4558c5aabdb4b190c47af1c4e443b" + integrity sha512-JER+w+9MV2MBVFOXxP036bLlNOnzbYAWrWU8sNUwoOO69T3w4564WhM5H5atd8VVS8U4vpi0i0kdoYzm1NPQgQ== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +esbuild-android-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3" + integrity sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg== + +esbuild-android-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz#6877566be0f82dd5a43030c0007d06ece7f7c02f" + integrity sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g== + +esbuild-darwin-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz#ea3caddb707d88f844b1aa1dea5ff3b0a71ef1fd" + integrity sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA== + +esbuild-darwin-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz#4e5eaab54df66cc319b76a2ac0e8af4e6f0d9c2f" + integrity sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA== + +esbuild-freebsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz#47b5abc7426eae66861490ffbb380acc67af5b15" + integrity sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA== + +esbuild-freebsd-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz#e8c54c8637cd44feed967ea12338b0a4da3a7b11" + integrity sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw== + +esbuild-linux-32@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz#229cf3246de2b7937c3ac13fac622d4d7a1344c5" + integrity sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ== + +esbuild-linux-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz#7c0e7226c02c42aacc5656c36977493dc1e96c4f" + integrity sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug== + +esbuild-linux-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz#0af1eda474b5c6cc0cace8235b74d0cb8fcf57a7" + integrity sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw== + +esbuild-linux-arm@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz#de4d1fa6b77cdcd00e2bb43dd0801e4680f0ab52" + integrity sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw== + +esbuild-linux-mips64le@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz#822c1778495f7868e990d4da47ad7281df28fd15" + integrity sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA== + +esbuild-linux-ppc64le@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz#55de0a9ec4a48fedfe82a63e083164d001709447" + integrity sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ== + +esbuild-linux-riscv64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz#cd2b7381880b2f4b21a5a598fb673492120f18a5" + integrity sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA== + +esbuild-linux-s390x@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz#4b319eca2a5c64637fc7397ffbd9671719cdb6bf" + integrity sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g== + +esbuild-netbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz#c27cde8b5cb55dcc227943a18ab078fb98d0adbf" + integrity sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw== + +esbuild-openbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz#af5ab2d1cb41f09064bba9465fc8bf1309150df1" + integrity sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA== + +esbuild-sunos-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz#db3ae20526055cf6fd5c4582676233814603ac54" + integrity sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA== + +esbuild-windows-32@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz#021ffceb0a3f83078262870da88a912293c57475" + integrity sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg== + +esbuild-windows-64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz#a4d3407b580f9faac51f61eec095fa985fb3fee4" + integrity sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA== + +esbuild-windows-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz#762c0562127d8b09bfb70a3c816460742dd82880" + integrity sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g== + +esbuild@^0.14.27: + version "0.14.48" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.48.tgz#da5d8d25cd2d940c45ea0cfecdca727f7aee2b85" + integrity sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA== + optionalDependencies: + esbuild-android-64 "0.14.48" + esbuild-android-arm64 "0.14.48" + esbuild-darwin-64 "0.14.48" + esbuild-darwin-arm64 "0.14.48" + esbuild-freebsd-64 "0.14.48" + esbuild-freebsd-arm64 "0.14.48" + esbuild-linux-32 "0.14.48" + esbuild-linux-64 "0.14.48" + esbuild-linux-arm "0.14.48" + esbuild-linux-arm64 "0.14.48" + esbuild-linux-mips64le "0.14.48" + esbuild-linux-ppc64le "0.14.48" + esbuild-linux-riscv64 "0.14.48" + esbuild-linux-s390x "0.14.48" + esbuild-netbsd-64 "0.14.48" + esbuild-openbsd-64 "0.14.48" + esbuild-sunos-64 "0.14.48" + esbuild-windows-32 "0.14.48" + esbuild-windows-64 "0.14.48" + esbuild-windows-arm64 "0.14.48" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +follow-redirects@^1.14.8: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hoist-non-react-statics@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +import-fresh@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.1, nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + +node-releases@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +postcss@^8.4.13: + version "8.4.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" + integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prettier@^2.5.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +prop-types@^15.6.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-refresh@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.13.0.tgz#cbd01a4482a177a5da8d44c9755ebb1f26d5a1c1" + integrity sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg== + +react-transition-group@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.12.0, resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rollup@^2.59.0: + version "2.75.7" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9" + integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ== + optionalDependencies: + fsevents "~2.3.2" + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +typescript@^4.5.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +update-browserslist-db@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz#dbfc5a789caa26b1db8990796c2c8ebbce304824" + integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +vite@^2.8.6: + version "2.9.13" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.13.tgz#859cb5d4c316c0d8c6ec9866045c0f7858ca6abc" + integrity sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw== + dependencies: + esbuild "^0.14.27" + postcss "^8.4.13" + resolve "^1.22.0" + rollup "^2.59.0" + optionalDependencies: + fsevents "~2.3.2" + +yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== diff --git a/src/lightning_app/components/python/popen.py b/src/lightning_app/components/python/popen.py index eb2ad978e3..553795d961 100644 --- a/src/lightning_app/components/python/popen.py +++ b/src/lightning_app/components/python/popen.py @@ -31,7 +31,7 @@ class PopenPythonScript(LightningWork): env: Optional[Dict] = None, **kwargs, ): - """The PopenPythonScript Class enables to easily run a Python Script. + """The PopenPythonScript component enables to easily run a python script within a subprocess. Arguments: script_path: Path of the python script to run. @@ -56,7 +56,7 @@ class PopenPythonScript(LightningWork): In this example, the script will be launch with the :class:`~subprocess.Popen`. - .. literalinclude:: ../../../../examples/components/python/component_popen.py + .. literalinclude:: ../../../../examples/app_components/python/component_popen.py :language: python """ super().__init__(**kwargs) diff --git a/src/lightning_app/components/python/tracer.py b/src/lightning_app/components/python/tracer.py index 5789b40dcc..5605eee6b6 100644 --- a/src/lightning_app/components/python/tracer.py +++ b/src/lightning_app/components/python/tracer.py @@ -33,9 +33,12 @@ class TracerPythonScript(LightningWork): env: Optional[Dict] = None, **kwargs, ): - """The TracerPythonScript Class enables to easily run a Python Script with Lightning - :class:`~lightning_app.utilities.tracer.Tracer`. Simply overrides the - :meth:`~lightning_app.components.python.tracer.TracerPythonScript.configure_tracer` method. + """The TracerPythonScript class enables to easily run a python script. + + When subclassing this class, you can configure your own :class:`~lightning_app.utilities.tracer.Tracer` + by :meth:`~lightning_app.components.python.tracer.TracerPythonScript.configure_tracer` method + + The tracer is quite a magical class. It enables you to inject core into a script execution without changing it. Arguments: script_path: Path of the python script to run. @@ -47,6 +50,13 @@ class TracerPythonScript(LightningWork): Raises: FileNotFoundError: If the provided `script_path` doesn't exists. + **How does it works ?** + + It works by executing the python script with python built-in `runpy + `_ run_path method. + This method takes any python globals before executing the script, + e.g you can modify classes or function from the script. + .. doctest:: >>> from lightning_app.components.python import TracerPythonScript @@ -59,17 +69,27 @@ class TracerPythonScript(LightningWork): Hello World ! >>> os.remove("a.py") - In this example, you would be able to implement your own :class:`~lightning_app.utilities.tracer.Tracer` - and intercept / modify elements while the script is being executed. + In the example below, we subclass the :class:`~lightning_app.components.python.TracerPythonScript` + component and override its configure_tracer method. - .. literalinclude:: ../../../../examples/components/python/component_tracer.py + Using the Tracer, we are patching the ``__init__`` method of the PyTorch Lightning Trainer. + Once the script starts running and if a Trainer is instantiated, the provided ``pre_fn`` is + called and we inject a Lightning callback. + + This callback has a reference to the work and on every batch end, we are capturing the + trainer ``global_step`` and ``best_model_path``. + + Even more interesting, this component works for ANY Pytorch Lightning script and + its state can be used in real time in a UI. + + .. literalinclude:: ../../../../examples/app_components/python/component_tracer.py :language: python Once implemented, this component can easily be integrated within a larger app to execute a specific python script. - .. literalinclude:: ../../../../examples/components/python/app.py + .. literalinclude:: ../../../../examples/app_components/python/app.py :language: python """ super().__init__(**kwargs) diff --git a/src/lightning_app/components/serve/gradio.py b/src/lightning_app/components/serve/gradio.py index 2376104894..ecbd583020 100644 --- a/src/lightning_app/components/serve/gradio.py +++ b/src/lightning_app/components/serve/gradio.py @@ -18,7 +18,7 @@ class ServeGradio(LightningWork, abc.ABC): In the example below, the ``ServeGradio`` is subclassed to deploy ``AnimeGANv2``. - .. literalinclude:: ../../../../examples/components/serve/gradio/app.py + .. literalinclude:: ../../../../examples/app_components/serve/gradio/app.py :language: python The result would be the following: diff --git a/src/lightning_app/core/app.py b/src/lightning_app/core/app.py index d9ecda0cfe..81a1a2115e 100644 --- a/src/lightning_app/core/app.py +++ b/src/lightning_app/core/app.py @@ -37,26 +37,33 @@ class LightningApp: root: "lightning_app.LightningFlow", debug: bool = False, ): - """LightningApp, or App in short, alternatively run its root - :class:`~lightning_app.core.flow.LightningFlow` component and collects state changes from external - sources to maintain the application state up-to-date or performs checkpointing. All those operations - are executed within an infinite loop. + """The Lightning App, or App in short runs a tree of one or more components that interact to create end-to-end + applications. There are two kinds of components: :class:`~lightning_app.core.flow.LightningFlow` and + :class:`~lightning_app.core.work.LightningWork`. This modular design enables you to reuse components + created by other users. + + The Lightning App alternatively run an event loop triggered by delta changes sent from + either :class:`~lightning.app.core.work.LightningWork` or from the Lightning UI. + Once deltas are received, the Lightning App runs + the :class:`~lightning.app.core.flow.LightningFlow` provided. Arguments: - root: The root LightningFlow component, that defined all the app's nested components, running infinitely. - debug: Whether to run the application in debug model. + root: The root LightningFlow component, that defined all + the app's nested components, running infinitely. + debug: Whether to activate the Lightning Logger debug mode. + This can be helpful when reporting bugs on Lightning repo. .. doctest:: - >>> from lightning_app import LightningFlow, LightningApp - >>> from lightning_app.runners import SingleProcessRuntime + >>> from lightning import LightningFlow, LightningApp + >>> from lightning.app.runners import MultiProcessRuntime >>> class RootFlow(LightningFlow): ... def run(self): ... print("Hello World!") ... self._exit() ... >>> app = LightningApp(RootFlow()) # application can be dispatched using the `runners`. - >>> SingleProcessRuntime(app).dispatch() + >>> MultiProcessRuntime(app).dispatch() Hello World! """ diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index 12056d0ce3..a5dcfd0a77 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -25,10 +25,10 @@ class LightningFlow: } def __init__(self): - """The LightningFlow is a building block to coordinate and manage long running-tasks contained within - :class:`~lightning_app.core.work.LightningWork` or nested LightningFlow. + """The LightningFlow is used by the :class:`~lightning_app.core.app.LightningApp` to coordinate and manage + long- running jobs contained, the :class:`~lightning_app.core.work.LightningWork`. - At a minimum, a LightningFlow is characterized by: + A LightningFlow is characterized by: * A set of state variables. * Long-running jobs (:class:`~lightning_app.core.work.LightningWork`). @@ -41,11 +41,6 @@ class LightningFlow: They also may not reach into global variables unless they are constant. - .. note :: - The limitation to primitive types will be lifted in time for - certain aggregate types, and will be made extensible so that component - developers will be able to add custom state-compatible types. - The attributes need to be all defined in `__init__` method, and eventually assigned to different values throughout the lifetime of the object. However, defining new attributes outside of `__init__` is not allowed. @@ -83,7 +78,7 @@ class LightningFlow: .. doctest:: - >>> from lightning_app import LightningFlow + >>> from lightning import LightningFlow >>> class RootFlow(LightningFlow): ... def __init__(self): ... super().__init__() @@ -345,6 +340,7 @@ class LightningFlow: return name in LightningFlow._INTERNAL_STATE_VARS or not name.startswith("_") def run(self, *args, **kwargs) -> None: + """Override with your own logic.""" pass def schedule( @@ -352,15 +348,16 @@ class LightningFlow: ) -> bool: """The schedule method is used to run a part of the flow logic on timely manner. - .. code-block:: + .. code-block:: python from lightning_app import LightningFlow - class Flow(LightningFlow): + class Flow(LightningFlow): def run(self): if self.schedule("hourly"): # run some code once every hour. + print("run this every hour") Arguments: cron_pattern: The cron pattern to provide. Learn more at https://crontab.guru/. @@ -370,7 +367,7 @@ class LightningFlow: A best practice is to avoid running a dynamic flow or work under the self.schedule method. Instead, instantiate them within the condition, but run them outside. - .. code-block:: python + .. code-block:: python from lightning_app import LightningFlow from lightning_app.structures import List @@ -382,11 +379,40 @@ class LightningFlow: self.dags = List() def run(self): - if self.schedule("@hourly"): + if self.schedule("hourly"): self.dags.append(DAG(...)) for dag in self.dags: payload = dag.run() + + **Learn more about Scheduling** + + .. raw:: html + +
+
+ + .. displayitem:: + :header: Schedule your components + :description: Learn more scheduling. + :col_css: col-md-4 + :button_link: ../../../glossary/scheduling.html + :height: 180 + :tag: Basic + + .. displayitem:: + :header: Build your own DAG + :description: Learn more DAG scheduling with examples. + :col_css: col-md-4 + :button_link: ../../../examples/app_dag/dag.html + :height: 180 + :tag: Basic + + .. raw:: html + +
+
+
""" if not user_key: frame = cast(FrameType, inspect.currentframe()).f_back @@ -454,40 +480,48 @@ class LightningFlow: **Example:** Serve a static directory (with at least a file index.html inside). - .. code-block:: + .. code-block:: python from lightning_app.frontend import StaticWebFrontend + class Flow(LightningFlow): ... + def configure_layout(self): return StaticWebFrontend("path/to/folder/to/serve") **Example:** Serve a streamlit UI (needs the streamlit package to be installed). - .. code-block:: + .. code-block:: python from lightning_app.frontend import StaticWebFrontend + class Flow(LightningFlow): ... + def configure_layout(self): return StreamlitFrontend(render_fn=my_streamlit_ui) + def my_streamlit_ui(state): # add your streamlit code here! + import streamlit as st + + st.button("Hello!") **Example:** Arrange the UI of my children in tabs (default UI by Lightning). - .. code-block:: + .. code-block:: python class Flow(LightningFlow): ... + def configure_layout(self): return [ dict(name="First Tab", content=self.child0), dict(name="Second Tab", content=self.child1), - ... # You can include direct URLs too dict(name="Lightning", content="https://lightning.ai"), ] @@ -500,6 +534,27 @@ class LightningFlow: returned layout configuration can depend on the state. The only exception are the flows that return a :class:`~lightning_app.frontend.frontend.Frontend`. These need to be provided at the time of app creation in order for the runtime to start the server. + + **Learn more about adding UI** + + .. raw:: html + +
+
+ + .. displayitem:: + :header: Add a web user interface (UI) + :description: Learn more how to integrate several UIs. + :col_css: col-md-4 + :button_link: ../../../workflows/add_web_ui/index.html + :height: 180 + :tag: Basic + + .. raw:: html + +
+
+
""" return [dict(name=name, content=component) for (name, component) in self.flows.items()] diff --git a/src/lightning_app/core/work.py b/src/lightning_app/core/work.py index 48a59ab447..0c12242e26 100644 --- a/src/lightning_app/core/work.py +++ b/src/lightning_app/core/work.py @@ -63,7 +63,31 @@ class LightningWork(abc.ABC): with the same arguments in subsequent calls. raise_exception: Whether to re-raise an exception in the flow when raised from within the work run method. host: Bind socket to this host - port: Bind socket to this port + port: Bind socket to this port. Be default, this is None and should be called within your run method. + local_build_config: The local BuildConfig isn't used until Lightning supports DockerRuntime. + cloud_build_config: The cloud BuildConfig enables user to easily configure machine before running this work. + run_once: Deprecated in favor of cache_calls. This will be removed soon. + + **Learn More About Lightning Work Inner Workings** + + .. raw:: html + +
+
+ + .. displayitem:: + :header: The Lightning Work inner workings. + :description: Learn more Lightning Work. + :col_css: col-md-4 + :button_link: ../../../core_api/lightning_work/index.html + :height: 180 + :tag: Basic + + .. raw:: html + +
+
+
""" from lightning_app.runners.backends.backend import Backend @@ -98,6 +122,7 @@ class LightningWork(abc.ABC): @property def url(self) -> str: + """Returns the current url of the work.""" return self._url @url.setter @@ -106,6 +131,7 @@ class LightningWork(abc.ABC): @property def host(self) -> str: + """Returns the current host of the work.""" return self._host @property @@ -166,6 +192,7 @@ class LightningWork(abc.ABC): @property def cloud_build_config(self) -> BuildConfig: + """Returns the cloud build config used to prepare the selected cloud hardware.""" return self._cloud_build_config @cloud_build_config.setter @@ -179,6 +206,7 @@ class LightningWork(abc.ABC): @cloud_compute.setter def cloud_compute(self, cloud_compute) -> None: + """Returns the cloud compute used to select the cloud hardware.""" self._cloud_compute = cloud_compute @property diff --git a/src/lightning_app/testing/helpers.py b/src/lightning_app/testing/helpers.py index 85bcbf33fa..f2e29b8213 100644 --- a/src/lightning_app/testing/helpers.py +++ b/src/lightning_app/testing/helpers.py @@ -23,7 +23,7 @@ def call_script( if args is None: args = [] args = [str(a) for a in args] - command = [sys.executable, "-m", "coverage", "run", filepath] + args + command = [sys.executable, filepath] + args # todo: add back coverage p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: stdout, stderr = p.communicate(timeout=timeout) diff --git a/src/lightning_app/testing/testing.py b/src/lightning_app/testing/testing.py index 72e7283a2a..7ae9bf6274 100644 --- a/src/lightning_app/testing/testing.py +++ b/src/lightning_app/testing/testing.py @@ -81,7 +81,7 @@ def application_testing(lightning_app_cls: Type[LightningTestApp], command_line: from click.testing import CliRunner - with mock.patch("lightning_app.LightningApp", lightning_app_cls): + with mock.patch("lightning.LightningApp", lightning_app_cls): runner = CliRunner() return runner.invoke(run_app, command_line, catch_exceptions=False) @@ -208,22 +208,14 @@ def run_app_in_cloud(app_folder: str, app_name: str = "app.py") -> Generator: """, [LIGHTNING_CLOUD_PROJECT_ID], ) - admin_page.reload() + admin_page.goto(f"{Config.url}/{Config.username}/apps") try: # Closing the Create Project modal button = admin_page.locator('button:has-text("Cancel")') - button.wait_for(timeout=1 * 1000) + button.wait_for(timeout=3 * 1000) button.click() except (playwright._impl._api_types.Error, playwright._impl._api_types.TimeoutError): pass - try: - # Skipping the Hubspot form - button = admin_page.locator('button:has-text("Skip for now")') - button.wait_for(timeout=1 * 1000) - button.click() - except (playwright._impl._api_types.Error, playwright._impl._api_types.TimeoutError): - pass - admin_page.goto(f"{Config.url}/{Config.username}/apps") admin_page.locator(f"text={name}").click() admin_page.evaluate( """data => { diff --git a/src/lightning_app/utilities/app_helpers.py b/src/lightning_app/utilities/app_helpers.py index b1834daa55..4144c6de3b 100644 --- a/src/lightning_app/utilities/app_helpers.py +++ b/src/lightning_app/utilities/app_helpers.py @@ -232,7 +232,7 @@ class StreamLitStatePlugin(BaseStatePlugin): # Adapted from -# https://github.com/Lightning-AI/lightning/blob/master/pytorch_lightning/utilities/model_helpers.py#L21 +# https://github.com/Lightning-AI/pytorch-lightning/blob/master/pytorch_lightning/utilities/model_helpers.py#L21 def is_overridden(method_name: str, instance: Optional[object] = None, parent: Optional[Type[object]] = None) -> bool: if instance is None: return False diff --git a/src/lightning_app/utilities/network.py b/src/lightning_app/utilities/network.py index fdd2a6dbfc..98c7db3d46 100644 --- a/src/lightning_app/utilities/network.py +++ b/src/lightning_app/utilities/network.py @@ -48,7 +48,7 @@ def _configure_session() -> Session: return http -def _check_service_url_is_ready(url: str, timeout: float = 0.1) -> bool: +def _check_service_url_is_ready(url: str, timeout: float = 0.5) -> bool: try: response = requests.get(url, timeout=timeout) return response.status_code in (200, 404) diff --git a/src/lightning_app/utilities/packaging/build_config.py b/src/lightning_app/utilities/packaging/build_config.py index 29d5ec2305..9231875d5d 100644 --- a/src/lightning_app/utilities/packaging/build_config.py +++ b/src/lightning_app/utilities/packaging/build_config.py @@ -1,12 +1,11 @@ import inspect import logging import os +import re from dataclasses import asdict, dataclass from types import FrameType from typing import cast, List, Optional, TYPE_CHECKING, Union -from pkg_resources import parse_requirements - if TYPE_CHECKING: from lightning_app import LightningWork from lightning_app.utilities.packaging.cloud_compute import CloudCompute @@ -15,6 +14,37 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) +def load_requirements( + path_dir: str, file_name: str = "base.txt", comment_char: str = "#", unfreeze: bool = True +) -> List[str]: + """Load requirements from a file. + + .. code-block:: python + + path_req = os.path.join(_PROJECT_ROOT, "requirements") + requirements = load_requirements(path_req) + print(requirements) # ['numpy...', 'torch...', ...] + """ + with open(os.path.join(path_dir, file_name)) as file: + lines = [ln.strip() for ln in file.readlines()] + reqs = [] + for ln in lines: + # filer all comments + comment = "" + if comment_char in ln: + comment = ln[ln.index(comment_char) :] + ln = ln[: ln.index(comment_char)] + req = ln.strip() + # skip directly installed dependencies + if not req or req.startswith("http") or "@http" in req: + continue + # remove version restrictions unless they are strict + if unfreeze and "<" in req and "strict" not in comment: + req = re.sub(r",? *<=? *[\d\.\*]+", "", req).strip() + reqs.append(req) + return reqs + + @dataclass class BuildConfig: """The Build Configuration describes how the environment a LightningWork runs in should be set up. @@ -61,7 +91,7 @@ class BuildConfig: class MyOwnBuildConfig(BuildConfig): def build_commands(self): - return ["sudo apt-get install libsparsehash-dev"] + return ["apt-get install libsparsehash-dev"] BuildConfig(requirements=["git+https://github.com/mit-han-lab/torchsparse.git@v1.4.0"]) """ @@ -84,8 +114,9 @@ class BuildConfig: requirement_files = [os.path.join(dirname, f) for f in os.listdir(dirname) if f == "requirements.txt"] if not requirement_files: return [] + dirname, basename = os.path.dirname(requirement_files[0]), os.path.basename(requirement_files[0]) try: - requirements = list(map(str, parse_requirements(open(requirement_files[0]).readlines()))) + requirements = load_requirements(dirname, basename) except NotADirectoryError: requirements = [] return [r for r in requirements if r != "lightning"] @@ -116,7 +147,9 @@ class BuildConfig: path = os.path.join(self._call_dir, req) if os.path.exists(path): try: - requirements.extend(list(map(str, parse_requirements(open(path).readlines())))) + requirements.extend( + load_requirements(os.path.dirname(path), os.path.basename(path)), + ) except NotADirectoryError: pass else: diff --git a/src/lightning_app/utilities/packaging/cloud_compute.py b/src/lightning_app/utilities/packaging/cloud_compute.py index 311e9acf75..6527911855 100644 --- a/src/lightning_app/utilities/packaging/cloud_compute.py +++ b/src/lightning_app/utilities/packaging/cloud_compute.py @@ -32,8 +32,8 @@ class CloudCompute: This timeout starts whenever your run() method succeeds (or fails). If the timeout is reached, the instance pauses until the next run() call happens. - shm_size: Shared memory size in MiB, backed by RAM. min 512, max 4096, it will auto update in steps of 512. - For example 1100 will become 1024. If set to zero (the default) will get the default 65MB inside docker. + shm_size: Shared memory size in MiB, backed by RAM. min 512, max 8192, it will auto update in steps of 512. + For example 1100 will become 1024. If set to zero (the default) will get the default 64MiB inside docker. """ name: str = "default" diff --git a/src/lightning_app/utilities/packaging/lightning_utils.py b/src/lightning_app/utilities/packaging/lightning_utils.py index 0eb1f6ba79..c6bcea0357 100644 --- a/src/lightning_app/utilities/packaging/lightning_utils.py +++ b/src/lightning_app/utilities/packaging/lightning_utils.py @@ -14,7 +14,7 @@ from typing import Any, Callable, Optional from packaging.version import Version from lightning_app import _logger, _PROJECT_ROOT, _root_logger -from lightning_app.__about__ import __version__ +from lightning_app.__version__ import version from lightning_app.core.constants import PREPARE_LIGHTING from lightning_app.utilities.git import check_github_repository, get_dir_name @@ -29,7 +29,7 @@ def download_frontend(root): """Downloads an archive file for a specific release of the Lightning frontend and extracts it to the correct directory.""" build_dir = "build" - frontend_dir = pathlib.Path(root, "lightning_app", "ui") + frontend_dir = pathlib.Path(root, "src", "lightning_app", "ui") download_dir = tempfile.mkdtemp() shutil.rmtree(frontend_dir, ignore_errors=True) @@ -43,41 +43,51 @@ def download_frontend(root): print("The Lightning UI has successfully been downloaded!") -def _cleanup(tar_file: str): - shutil.rmtree(os.path.join(_PROJECT_ROOT, "dist"), ignore_errors=True) - os.remove(tar_file) +def _cleanup(*tar_files: str): + for tar_file in tar_files: + shutil.rmtree(os.path.join(_PROJECT_ROOT, "dist"), ignore_errors=True) + os.remove(tar_file) -def _prepare_lightning_wheels(): +def _prepare_wheel(path): with open("log.txt", "w") as logfile: with subprocess.Popen( - ["rm", "-r", "dist"], stdout=logfile, stderr=logfile, bufsize=0, close_fds=True, cwd=_PROJECT_ROOT + ["rm", "-r", "dist"], stdout=logfile, stderr=logfile, bufsize=0, close_fds=True, cwd=path ) as proc: proc.wait() - with subprocess.Popen( ["python", "setup.py", "sdist"], stdout=logfile, stderr=logfile, bufsize=0, close_fds=True, - cwd=_PROJECT_ROOT, + cwd=path, ) as proc: proc.wait() os.remove("log.txt") -def _copy_lightning_tar(root: Path) -> str: - dist_dir = os.path.join(_PROJECT_ROOT, "dist") +def _copy_tar(project_root, dest: Path) -> str: + dist_dir = os.path.join(project_root, "dist") tar_files = os.listdir(dist_dir) assert len(tar_files) == 1 tar_name = tar_files[0] tar_path = os.path.join(dist_dir, tar_name) - shutil.copy(tar_path, root) + shutil.copy(tar_path, dest) return tar_name +def get_dist_path_if_editable_install(project_name) -> str: + """Is distribution an editable install - modified version from pip that + fetches egg-info instead of egg-link""" + for path_item in sys.path: + egg_info = os.path.join(path_item, project_name + ".egg-info") + if os.path.isdir(egg_info): + return path_item + return "" + + def _prepare_lightning_wheels_and_requirements(root: Path) -> Optional[Callable]: if "site-packages" in _PROJECT_ROOT: @@ -88,20 +98,37 @@ def _prepare_lightning_wheels_and_requirements(root: Path) -> Optional[Callable] if not PREPARE_LIGHTING and (not git_dir_name or (git_dir_name and not git_dir_name.startswith("lightning"))): return - if not bool(int(os.getenv("SKIP_LIGHTING_WHEELS_BUILD", "0"))): download_frontend(_PROJECT_ROOT) - _prepare_lightning_wheels() + _prepare_wheel(_PROJECT_ROOT) logger.info("Packaged Lightning with your application.") - tar_name = _copy_lightning_tar(root) + tar_name = _copy_tar(_PROJECT_ROOT, root) - return functools.partial(_cleanup, tar_file=os.path.join(root, tar_name)) + tar_files = [os.path.join(root, tar_name)] + + # skipping this by default + if not bool(int(os.getenv("SKIP_LIGHTING_UTILITY_WHEELS_BUILD", "1"))): + # building and copying launcher wheel if installed in editable mode + launcher_project_path = get_dist_path_if_editable_install("lightning_launcher") + if launcher_project_path: + _prepare_wheel(launcher_project_path) + tar_name = _copy_tar(launcher_project_path, root) + tar_files.append(os.path.join(root, tar_name)) + + # building and copying lightning-cloud wheel if installed in editable mode + lightning_cloud_project_path = get_dist_path_if_editable_install("lightning_cloud") + if lightning_cloud_project_path: + _prepare_wheel(lightning_cloud_project_path) + tar_name = _copy_tar(lightning_cloud_project_path, root) + tar_files.append(os.path.join(root, tar_name)) + + return functools.partial(_cleanup, *tar_files) def _enable_debugging(): - tar_file = os.path.join(os.getcwd(), f"lightning-{__version__}.tar.gz") + tar_file = os.path.join(os.getcwd(), f"lightning-{version}.tar.gz") if not os.path.exists(tar_file): return @@ -138,7 +165,7 @@ def _fetch_latest_version(package_name: str) -> str: if proc.stdout: logs = " ".join([line.decode("utf-8") for line in iter(proc.stdout.readline, b"")]) return logs.split(")\n")[0].split(",")[-1].replace(" ", "") - return __version__ + return version def _verify_lightning_version(): @@ -149,7 +176,7 @@ def _verify_lightning_version(): lightning_latest_version = _fetch_latest_version("lightning") - if Version(lightning_latest_version) > Version(__version__): + if Version(lightning_latest_version) > Version(version): raise Exception( f"You need to use the latest version of Lightning ({lightning_latest_version}) to run in the cloud. " "Please, run `pip install -U lightning`" diff --git a/tests/tests_app/cli/test_cmd_react_ui_init.py b/tests/tests_app/cli/test_cmd_react_ui_init.py index 7ad248084b..0a54c478c4 100644 --- a/tests/tests_app/cli/test_cmd_react_ui_init.py +++ b/tests/tests_app/cli/test_cmd_react_ui_init.py @@ -56,4 +56,4 @@ def test_copy_and_setup_react_ui(tmpdir): def test_correct_num_react_template_files(): template_dir = os.path.join(la.__path__[0], "cli/react-ui-template") files = cmd_init._ls_recursively(template_dir) - assert len(files) == 15, "react-ui template files must be minimal... do not add nice to haves" + assert len(files) == 16, "react-ui template files must be minimal... do not add nice to haves" diff --git a/tests/tests_app/utilities/packaging/test_lightning_utils.py b/tests/tests_app/utilities/packaging/test_lightning_utils.py index 0e4a370b40..b34e3162d5 100644 --- a/tests/tests_app/utilities/packaging/test_lightning_utils.py +++ b/tests/tests_app/utilities/packaging/test_lightning_utils.py @@ -2,7 +2,7 @@ import os import pytest -from lightning import __about__ +from lightning.__version__ import version from lightning_app.testing.helpers import RunIf from lightning_app.utilities.packaging import lightning_utils from lightning_app.utilities.packaging.lightning_utils import ( @@ -15,7 +15,7 @@ def test_prepare_lightning_wheels_and_requirement(tmpdir): """This test ensures the lightning source gets packaged inside the lightning repo.""" cleanup_handle = _prepare_lightning_wheels_and_requirements(tmpdir) - tar_name = f"lightning-{__about__.__version__}.tar.gz" + tar_name = f"lightning-{version}.tar.gz" assert sorted(os.listdir(tmpdir)) == [tar_name] cleanup_handle() assert os.listdir(tmpdir) == [] diff --git a/tests/tests_app/utilities/test_git.py b/tests/tests_app/utilities/test_git.py index efb59d05ad..cb2db0a2bf 100644 --- a/tests/tests_app/utilities/test_git.py +++ b/tests/tests_app/utilities/test_git.py @@ -15,7 +15,7 @@ def test_execute_git_command(): res = execute_git_command(["pull"]) assert res - assert get_dir_name() == "lightning-app" + assert get_dir_name() == "lightning" assert check_github_repository()