Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Releasing/1.8.4.post #15988

Merged
merged 11 commits into from
Dec 9, 2022
14 changes: 14 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,20 @@ and the last true master commit is `ccc111` and your first commit is `mmm222`.
git push -f
```

#### How to run an app on the cloud with a local version of lightning

The lightning cloud uses the latest release by default. However, you might want to run your app with some local changes you've made to the lightning framework. To use your local version of lightning on the cloud, set the following environment variable:

```bash
git clone https://github.com/Lightning-AI/lightning.git
cd lightning
pip install -e .
export PACKAGE_LIGHTNING=1 # <- this is the magic to use your version (not mainstream PyPI)!
lightning run app app.py --cloud
```

By seting `PACKAGE_LIGHTNING=1`, lightning packages the lightning source code in your local directory in addition to your app source code and uploads them to the cloud.

### Bonus Workflow Tip

If you don't want to remember all the commands above every time you want to push some code/setup a Lightning Dev environment on a new VM, you can set up bash aliases for some common commands. You can add these to one of your `~/.bashrc`, `~/.zshrc`, or `~/.bash_aliases` files.
Expand Down
36 changes: 18 additions & 18 deletions .github/workflows/release-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defaults:
shell: bash

jobs:

init:
runs-on: ubuntu-20.04
steps:
Expand All @@ -23,6 +24,7 @@ jobs:
name: dist-packages-${{ github.sha }}
path: dist


build-packages:
needs: init
runs-on: ubuntu-20.04
Expand All @@ -40,22 +42,20 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: 3.9

- name: Install dependencies
run: pip install -U setuptools wheel

- name: Build packages
env:
PACKAGE_NAME: ${{ matrix.pkg-name }}
run: |
python setup.py sdist bdist_wheel
ls -lh dist/

- uses: actions/upload-artifact@v3
with:
name: dist-packages-${{ github.sha }}
path: dist


upload-packages:
runs-on: ubuntu-20.04
needs: build-packages
Expand All @@ -73,6 +73,7 @@ jobs:
files: 'dist/*'
repo-token: ${{ secrets.GITHUB_TOKEN }}


release-version:
runs-on: ubuntu-20.04
outputs:
Expand All @@ -87,6 +88,7 @@ jobs:
id: lai-package
run: python -c "import lightning as L; print(f'version={L.__version__}')" >> $GITHUB_OUTPUT


signaling:
runs-on: ubuntu-20.04
needs: [release-version]
Expand All @@ -100,12 +102,6 @@ jobs:
with:
repository: gridai/base-images
token: ${{ secrets.PAT_GHOST }}
ref: main
- uses: fregante/setup-git-token@v1
with:
token: ${{ secrets.PAT_GHOST }}
name: PL Ghost
email: [email protected]
- name: Update lightning version
run: |
import json, os
Expand All @@ -115,20 +111,21 @@ jobs:
with open("versions.json", "w") as fw:
json.dump(vers, fw)
shell: python
- name: GIT Commit
- run: cat versions.json
- name: GIT commit & push
env:
BRANCH_NAME: "trigger/lightning-${{ env.TAG }}"
run: |
git config --global user.name "PL Ghost"
git config --global user.email [email protected]
git checkout -b ${BRANCH_NAME}
git add versions.json
git commit -m "bumping lightning version -> ${TAG}"
cat versions.json
- name: GIT Push
run: |
git status
# force push is not very nice
# but so far the push is rejected even with exception for this user
git push -f
git commit -m "bumping lightning version -> ${TAG}"
git push -u origin ${BRANCH_NAME} -f


waiting:
# TODO: replace with back signal from build images/ loop checking for a specific branch?
runs-on: ubuntu-20.04
needs: [release-version, signaling]
env:
Expand All @@ -152,6 +149,7 @@ jobs:
time.sleep(60)
shell: python


pre-publish-packages:
runs-on: ubuntu-20.04
needs: build-packages
Expand Down Expand Up @@ -181,6 +179,7 @@ jobs:
pkg-pattern: "*"
pypi-test-token: ${{ secrets.PYPI_TEST_TOKEN_LAI }}


publish-packages:
runs-on: ubuntu-20.04
needs: [build-packages, waiting]
Expand Down Expand Up @@ -210,6 +209,7 @@ jobs:
pkg-pattern: "*"
pypi-token: ${{ secrets.PYPI_TOKEN_LAI }}


legacy-checkpoints:
needs: [build-packages]
uses: ./.github/workflows/legacy-checkpoints.yml
Expand Down
21 changes: 12 additions & 9 deletions examples/app_server_with_auto_scaler/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ! pip install torch torchvision
from typing import Any, List

import torch
Expand All @@ -22,10 +23,10 @@ class BatchResponse(BaseModel):
class PyTorchServer(L.app.components.PythonServer):
def __init__(self, *args, **kwargs):
super().__init__(
port=L.app.utilities.network.find_free_network_port(),
input_type=BatchRequestModel,
output_type=BatchResponse,
cloud_compute=L.CloudCompute("gpu"),
*args,
**kwargs,
)

def setup(self):
Expand Down Expand Up @@ -57,30 +58,32 @@ def scale(self, replicas: int, metrics: dict) -> int:
"""The default scaling logic that users can override."""
# scale out if the number of pending requests exceeds max batch size.
max_requests_per_work = self.max_batch_size
pending_requests_per_running_or_pending_work = metrics["pending_requests"] / (
replicas + metrics["pending_works"]
)
if pending_requests_per_running_or_pending_work >= max_requests_per_work:
pending_requests_per_work = metrics["pending_requests"] / (replicas + metrics["pending_works"])
if pending_requests_per_work >= max_requests_per_work:
return replicas + 1

# scale in if the number of pending requests is below 25% of max_requests_per_work
min_requests_per_work = max_requests_per_work * 0.25
pending_requests_per_running_work = metrics["pending_requests"] / replicas
if pending_requests_per_running_work < min_requests_per_work:
pending_requests_per_work = metrics["pending_requests"] / replicas
if pending_requests_per_work < min_requests_per_work:
return replicas - 1

return replicas


app = L.LightningApp(
MyAutoScaler(
# work class and args
PyTorchServer,
min_replicas=2,
cloud_compute=L.CloudCompute("gpu"),
# autoscaler specific args
min_replicas=1,
max_replicas=4,
autoscale_interval=10,
endpoint="predict",
input_type=RequestModel,
output_type=Any,
timeout_batching=1,
max_batch_size=8,
)
)
2 changes: 0 additions & 2 deletions requirements/app/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,3 @@ beautifulsoup4>=4.8.0, <4.11.2
inquirer>=2.10.0
psutil<5.9.4
click<=8.1.3
s3fs>=2022.5.0, <2022.8.3
aiohttp>=3.8.0, <=3.8.3
2 changes: 2 additions & 0 deletions requirements/app/cloud.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
redis>=4.0.1, <=4.2.4
docker>=5.0.0, <=5.0.3
# setuptools==59.5.0
s3fs>=2022.5.0, <2022.8.3
aiohttp>=3.8.0, <=3.8.3
1 change: 1 addition & 0 deletions requirements/app/components.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# deps required by components in the lightning app repository (src/lightning_app/components)
lightning_api_access>=0.0.3
aiohttp>=3.8.0, <=3.8.3
2 changes: 1 addition & 1 deletion src/lightning/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = "1.8.4"
version = "1.8.4.post0"
10 changes: 9 additions & 1 deletion src/lightning_app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added the CLI command `lightning delete app` to delete a lightning app on the cloud ([#15783](https://github.com/Lightning-AI/lightning/pull/15783))
- Added a CloudMultiProcessBackend which enables running a child App from within the Flow in the cloud ([#15800](https://github.com/Lightning-AI/lightning/pull/15800))
- Utility for pickling work object safely even from a child process ([#15836](https://github.com/Lightning-AI/lightning/pull/15836))
- Added `AutoScaler` component ([#15769](https://github.com/Lightning-AI/lightning/pull/15769))
- Added `AutoScaler` component (
[#15769](https://github.com/Lightning-AI/lightning/pull/15769),
[#15971](https://github.com/Lightning-AI/lightning/pull/15971),
[#15966](https://github.com/Lightning-AI/lightning/pull/15966)
)
- Added the property `ready` of the LightningFlow to inform when the `Open App` should be visible ([#15921](https://github.com/Lightning-AI/lightning/pull/15921))
- Added private work attributed `_start_method` to customize how to start the works ([#15923](https://github.com/Lightning-AI/lightning/pull/15923))
- Added a `configure_layout` method to the `LightningWork` which can be used to control how the work is handled in the layout of a parent flow ([#15926](https://github.com/Lightning-AI/lightning/pull/15926))
Expand Down Expand Up @@ -50,6 +54,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Fixed multiprocessing breakpoint ([#15950](https://github.com/Lightning-AI/lightning/pull/15950))
- Fixed detection of a Lightning App running in debug mode ([#15951](https://github.com/Lightning-AI/lightning/pull/15951))
- Fixed `ImportError` on Multinode if package not present ([#15963](https://github.com/Lightning-AI/lightning/pull/15963))
- Fixed MultiNode Component to use separate cloud computes ([#15965](https://github.com/Lightning-AI/lightning/pull/15965))
- Fixed Registration for CloudComputes of Works in `L.app.structures` ([#15964](https://github.com/Lightning-AI/lightning/pull/15964))
- Fixed a bug where auto-upgrading to the latest lightning via the CLI could get stuck in a loop ([#15984](https://github.com/Lightning-AI/lightning/pull/15984))


## [1.8.3] - 2022-11-22

Expand Down
2 changes: 1 addition & 1 deletion src/lightning_app/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version = "1.8.4"
version = "1.8.4.post0"
15 changes: 9 additions & 6 deletions src/lightning_app/cli/cmd_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def gallery_apps_and_components(
except Exception:
return None

entry, kind = _resolve_entry(app_or_component, version_arg)
entry, kind = _resolve_entry(name, version_arg)

if kind == "app":
# give the user the chance to do a manual install
Expand All @@ -111,16 +111,19 @@ def gallery_apps_and_components(
# run installation if requested
_install_app_from_source(source_url, git_url, folder_name, cwd=cwd, overwrite=overwrite, git_sha=git_sha)

return os.path.join(os.getcwd(), folder_name, entry["appEntrypointFile"])
return os.path.join(os.getcwd(), *entry["appEntrypointFile"].split("/"))

elif kind == "component":
# give the user the chance to do a manual install
git_url = _show_install_component_prompt(entry, app_or_component, org, yes_arg)

source_url, git_url, folder_name, git_sha = _show_install_app_prompt(
entry, app_or_component, org, yes_arg, resource_type="component"
)
if "@" in git_url:
git_url = git_url.split("git+")[1].split("@")[0]
# run installation if requested
_install_component_from_source(git_url)
_install_app_from_source(source_url, git_url, folder_name, cwd=cwd, overwrite=overwrite, git_sha=git_sha)

return os.path.join(os.getcwd(), entry["appEntrypointFile"])
return os.path.join(os.getcwd(), *entry["entrypointFile"].split("/"))

return None

Expand Down
5 changes: 3 additions & 2 deletions src/lightning_app/cli/lightning_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@


def main() -> None:
# Check environment and versions if not in the cloud
if "LIGHTNING_APP_STATE_URL" not in os.environ:
# Check environment and versions if not in the cloud and not testing
is_testing = bool(int(os.getenv("LIGHTING_TESTING", "0")))
if not is_testing and "LIGHTNING_APP_STATE_URL" not in os.environ:
# Enforce running in PATH Python
_check_environment_and_redirect()

Expand Down
11 changes: 8 additions & 3 deletions src/lightning_app/components/auto_scaler.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from itertools import cycle
from typing import Any, Dict, List, Tuple, Type

import aiohttp
import aiohttp.client_exceptions
import requests
import uvicorn
from fastapi import Depends, FastAPI, HTTPException, Request
Expand All @@ -22,8 +20,13 @@
from lightning_app.core.flow import LightningFlow
from lightning_app.core.work import LightningWork
from lightning_app.utilities.app_helpers import Logger
from lightning_app.utilities.imports import _is_aiohttp_available, requires
from lightning_app.utilities.packaging.cloud_compute import CloudCompute

if _is_aiohttp_available():
import aiohttp
import aiohttp.client_exceptions

logger = Logger(__name__)


Expand Down Expand Up @@ -114,6 +117,7 @@ class _LoadBalancer(LightningWork):
\**kwargs: Arguments passed to :func:`LightningWork.init` like ``CloudCompute``, ``BuildConfig``, etc.
"""

@requires(["aiohttp"])
def __init__(
self,
input_type: BaseModel,
Expand Down Expand Up @@ -446,7 +450,8 @@ def workers(self) -> List[LightningWork]:
def create_work(self) -> LightningWork:
"""Replicates a LightningWork instance with args and kwargs provided via ``__init__``."""
# TODO: Remove `start_with_flow=False` for faster initialization on the cloud
return self._work_cls(*self._work_args, **self._work_kwargs, start_with_flow=False)
self._work_kwargs.update(dict(start_with_flow=False))
return self._work_cls(*self._work_args, **self._work_kwargs)

def add_work(self, work) -> str:
"""Adds a new LightningWork instance.
Expand Down
2 changes: 1 addition & 1 deletion src/lightning_app/components/multi_node/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def run(
*[
work_cls(
*work_args,
cloud_compute=cloud_compute,
cloud_compute=cloud_compute.clone(),
**work_kwargs,
parallel=True,
)
Expand Down
6 changes: 1 addition & 5 deletions src/lightning_app/components/serve/python_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,13 @@ class PythonServer(LightningWork, abc.ABC):
@requires(["torch", "lightning_api_access"])
def __init__( # type: ignore
self,
host: str = "127.0.0.1",
port: int = 7777,
input_type: type = _DefaultInputData,
output_type: type = _DefaultOutputData,
**kwargs,
):
"""The PythonServer Class enables to easily get your machine learning server up and running.

Arguments:
host: Address to be used for running the server.
port: Port to be used to running the server.
input_type: Optional `input_type` to be provided. This needs to be a pydantic BaseModel class.
The default data type is good enough for the basic usecases and it expects the data
to be a json object that has one key called `payload`
Expand Down Expand Up @@ -129,7 +125,7 @@ def predict(self, request):
...
>>> app = LightningApp(SimpleServer())
"""
super().__init__(parallel=True, host=host, port=port, **kwargs)
super().__init__(parallel=True, **kwargs)
if not issubclass(input_type, BaseModel):
raise TypeError("input_type must be a pydantic BaseModel class")
if not issubclass(output_type, BaseModel):
Expand Down
19 changes: 13 additions & 6 deletions src/lightning_app/core/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,19 @@ def __setattr__(self, name: str, value: Any) -> None:
elif isinstance(value, (Dict, List)):
self._structures.add(name)
_set_child_name(self, value, name)
if getattr(self, "_backend", None) is not None:
value._backend = self._backend
for flow in value.flows:
LightningFlow._attach_backend(flow, self._backend)
for work in value.works:
self._backend._wrap_run_method(_LightningAppRef().get_current(), work)

_backend = getattr(self, "backend", None)
if _backend is not None:
value._backend = _backend

for flow in value.flows:
if _backend is not None:
LightningFlow._attach_backend(flow, _backend)

for work in value.works:
work._register_cloud_compute()
if _backend is not None:
_backend._wrap_run_method(_LightningAppRef().get_current(), work)

elif isinstance(value, Path):
# In the init context, the full name of the Flow and Work is not known, i.e., we can't serialize
Expand Down
Loading