Skip to content

Commit

Permalink
Merge branch 'main' into feature/reports
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
  • Loading branch information
mihran113 committed Sep 15, 2024
2 parents 80b5591 + a566d4a commit 7b56361
Show file tree
Hide file tree
Showing 18 changed files with 96 additions and 16 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@
### Enhancements:
- Add ability to create reports (mihran113)

### Fixes:
## 3.24.0 Aug 14, 2024

### Enhancements
- Add read-only mode for Aim UI (mihran113)
- Support of mass updates in remote tracking (peter-sk)

### Fixes
- Fix bug in bookmark page where it was not scrollable if there was too many bookmarks (vinayan3)
- Fix exception name in `storage/union.pyx` (sulan)

## 3.23.0 Jul 15, 2024

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ These command will create a folder named `ComponentName` with all the necessary
Aim documentation is built using [Sphix](https://www.sphinx-doc.org) and is hosted at
[Read the Docs](https://aimstack.readthedocs.io).
The documentation sources are located at `docs/` directory. In order to build documentation locally
run the following commands
run the following commands with a Python interpreter version <= 3.10:
```shell
pip install -r requirements.dev.txt
cd docs
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Check out live Aim demos NOW to see it in action.
| <a href="https://play.aimstack.io/nmt/metrics?grouping=O-JTdCJTIyY29sb3IlMjI6JTVCJTIycnVuLnBhcmFtcy5ocGFyYW1zLm1heF9rJTIyJTVELCUyMnN0cm9rZSUyMjolNUIlNUQsJTIyY2hhcnQlMjI6JTVCJTIybmFtZSUyMiwlMjJjb250ZXh0LnN1YnNldCUyMiU1RCwlMjJyZXZlcnNlTW9kZSUyMjolN0IlMjJjb2xvciUyMjpmYWxzZSwlMjJzdHJva2UlMjI6ZmFsc2UsJTIyY2hhcnQlMjI6ZmFsc2UlN0QsJTIyaXNBcHBsaWVkJTIyOiU3QiUyMmNvbG9yJTIyOnRydWUsJTIyc3Ryb2tlJTIyOnRydWUsJTIyY2hhcnQlMjI6dHJ1ZSU3RCwlMjJwZXJzaXN0ZW5jZSUyMjolN0IlMjJjb2xvciUyMjpmYWxzZSwlMjJzdHJva2UlMjI6ZmFsc2UlN0QsJTIyc2VlZCUyMjolN0IlMjJjb2xvciUyMjoxMCwlMjJzdHJva2UlMjI6MTAlN0QsJTIycGFsZXR0ZUluZGV4JTIyOjAlN0Q&chart=O-JTdCJTIyaGlnaGxpZ2h0TW9kZSUyMjoyLCUyMmlnbm9yZU91dGxpZXJzJTIyOnRydWUsJTIyem9vbSUyMjolN0IlMjJhY3RpdmUlMjI6ZmFsc2UsJTIybW9kZSUyMjowLCUyMmhpc3RvcnklMjI6JTVCJTVEJTdELCUyMmF4ZXNTY2FsZVR5cGUlMjI6JTdCJTIyeEF4aXMlMjI6JTIybGluZWFyJTIyLCUyMnlBeGlzJTIyOiUyMmxpbmVhciUyMiU3RCwlMjJheGVzU2NhbGVSYW5nZSUyMjolN0IlMjJ5QXhpcyUyMjolN0IlN0QsJTIyeEF4aXMlMjI6JTdCJTdEJTdELCUyMnNtb290aGluZyUyMjolN0IlMjJhbGdvcml0aG0lMjI6JTIyRVhQT05FTlRJQUxfTU9WSU5HX0FWRVJBR0UlMjIsJTIyZmFjdG9yJTIyOjAsJTIyY3VydmVJbnRlcnBvbGF0aW9uJTIyOiUyMmN1cnZlTGluZWFyJTIyLCUyMmlzQXBwbGllZCUyMjpmYWxzZSU3RCwlMjJhbGlnbm1lbnRDb25maWclMjI6JTdCJTIybWV0cmljJTIyOiUyMiUyMiwlMjJ0eXBlJTIyOiUyMnN0ZXAlMjIlN0QsJTIyZGVuc2l0eVR5cGUlMjI6NTAwLCUyMmFnZ3JlZ2F0aW9uQ29uZmlnJTIyOiU3QiUyMm1ldGhvZHMlMjI6JTdCJTIyYXJlYSUyMjoxLCUyMmxpbmUlMjI6MCU3RCwlMjJpc0FwcGxpZWQlMjI6dHJ1ZSwlMjJpc0VuYWJsZWQlMjI6dHJ1ZSU3RCwlMjJ0b29sdGlwJTIyOiU3QiUyMmFwcGVhcmFuY2UlMjI6JTIyYXV0byUyMiwlMjJkaXNwbGF5JTIyOnRydWUsJTIyc2VsZWN0ZWRGaWVsZHMlMjI6JTVCJTVELCUyMnNlbGVjdGVkUGFyYW1zJTIyOiU1QiU1RCU3RCwlMjJsZWdlbmRzJTIyOiU3QiUyMmRpc3BsYXklMjI6dHJ1ZSwlMjJtb2RlJTIyOiUyMnBpbm5lZCUyMiU3RCwlMjJmb2N1c2VkU3RhdGUlMjI6JTdCJTIyYWN0aXZlJTIyOnRydWUsJTIya2V5JTIyOiUyMk8tSlRkQ0pUSXljblZ1U0dGemFDVXlNam9sTWpKa1lUTmtNV1UzSlRJeUxDVXlNbTFsZEhKcFkwNWhiV1VsTWpJNkpUSXlZbVZ6ZEY5c2IzTnpKVEl5TENVeU1uUnlZV05sUTI5dWRHVjRkQ1V5TWpvbE4wSWxNakp6ZFdKelpYUWxNakk2SlRJeWRtRnNKVEl5SlRkRUpUZEUlMjIsJTIyeFZhbHVlJTIyOjIxLCUyMnlWYWx1ZSUyMjozLjQ3Mzk5OTk3NzEsJTIyY2hhcnRJbmRleCUyMjowLCUyMnZpc0lkJTIyOiUyMjAlMjIlN0QlN0Q&select=O-JTdCJTIyb3B0aW9ucyUyMjolNUIlN0IlMjJsYWJlbCUyMjolMjJiZXN0X2xvc3MlMjIsJTIyZ3JvdXAlMjI6JTIyYmVzdF9sb3NzJTIyLCUyMnR5cGUlMjI6JTIybWV0cmljcyUyMiwlMjJjb2xvciUyMjolMjIjN0E0Q0UwJTIyLCUyMmtleSUyMjolMjJPLUpUZENKVEl5YldWMGNtbGpUbUZ0WlNVeU1qb2xNakppWlhOMFgyeHZjM01sTWpJc0pUSXlZMjl1ZEdWNGRFNWhiV1VsTWpJNkpUSXlKVEl5SlRkRSUyMiwlMjJ2YWx1ZSUyMjolN0IlMjJvcHRpb25fbmFtZSUyMjolMjJiZXN0X2xvc3MlMjIsJTIyY29udGV4dCUyMjpudWxsJTdEJTdELCU3QiUyMmxhYmVsJTIyOiUyMmJsZXUlMjIsJTIyZ3JvdXAlMjI6JTIyYmxldSUyMiwlMjJ0eXBlJTIyOiUyMm1ldHJpY3MlMjIsJTIyY29sb3IlMjI6JTIyIzNFNzJFNyUyMiwlMjJrZXklMjI6JTIyTy1KVGRDSlRJeWJXVjBjbWxqVG1GdFpTVXlNam9sTWpKaWJHVjFKVEl5TENVeU1tTnZiblJsZUhST1lXMWxKVEl5T2lVeU1pVXlNaVUzUkElMjIsJTIydmFsdWUlMjI6JTdCJTIyb3B0aW9uX25hbWUlMjI6JTIyYmxldSUyMiwlMjJjb250ZXh0JTIyOm51bGwlN0QlN0QlNUQsJTIycXVlcnklMjI6JTIycnVuLmhwYXJhbXMubGVhcm5pbmdfcmF0ZSUyMCUzRSUyMDAuMDAwMDElMjIsJTIyYWR2YW5jZWRNb2RlJTIyOmZhbHNlLCUyMmFkdmFuY2VkUXVlcnklMjI6JTIycnVuLmhwYXJhbXMubGVhcm5pbmdfcmF0ZSUyMCUzRSUyMDAuMDAwMDElMjBhbmQlMjAoKG1ldHJpYy5uYW1lJTIwPT0lMjAlNUMlMjJibGV1JTVDJTIyKSUyMG9yJTIwKG1ldHJpYy5uYW1lJTIwPT0lMjAlNUMlMjJiZXN0X2xvc3MlNUMlMjIpJTIwb3IlMjAobWV0cmljLm5hbWUlMjA9PSUyMCU1QyUyMmJzeiU1QyUyMiUyMGFuZCUyMG1ldHJpYy5jb250ZXh0LnN1YnNldCUyMD09JTIwJTVDJTIydHJhaW4lNUMlMjIpKSUyMiU3RA"> <img src="https://user-images.githubusercontent.com/97726819/225964524-0051c2c7-8554-43ae-82b8-adcb77bcf1ba.png"> </a> | <a href="https://play.aimstack.io/image-generation/images?grouping=O-JTdCJTIycm93JTIyOiU1QiU1RCwlMjJyZXZlcnNlTW9kZSUyMjolN0IlMjJyb3clMjI6ZmFsc2UsJTIyZ3JvdXAlMjI6ZmFsc2UlN0QsJTIyaXNBcHBsaWVkJTIyOiU3QiUyMnJvdyUyMjp0cnVlLCUyMmdyb3VwJTIyOnRydWUlN0QsJTIyZ3JvdXAlMjI6JTVCJTIyaW5kZXglMjIsJTIyc3RlcCUyMiU1RCU3RA&select=O-JTdCJTIyb3B0aW9ucyUyMjolNUIlN0IlMjJsYWJlbCUyMjolMjJnZW5lcmF0ZWQlMjIsJTIyZ3JvdXAlMjI6JTIyZ2VuZXJhdGVkJTIyLCUyMmNvbG9yJTIyOiUyMiMzRTcyRTclMjIsJTIya2V5JTIyOiUyMk8tSlRkQ0pUSXliV1YwY21salRtRnRaU1V5TWpvbE1qSm5aVzVsY21GMFpXUWxNaklzSlRJeVkyOXVkR1Y0ZEU1aGJXVWxNakk2SlRJeUpUSXlKVGRFJTIyLCUyMnZhbHVlJTIyOiU3QiUyMm9wdGlvbl9uYW1lJTIyOiUyMmdlbmVyYXRlZCUyMiwlMjJjb250ZXh0JTIyOm51bGwlN0QlN0QlNUQsJTIycXVlcnklMjI6JTIyaW1hZ2VzLmNvbnRleHQuaW50ZXJwb2xhdGVkJTIwYW5kJTIwcnVuLmhwYXJhbXMubmFtZSUyMD09JTIwJTVDJTIybWV0ZmFjZXMlNUMlMjIlMjIsJTIyYWR2YW5jZWRNb2RlJTIyOmZhbHNlLCUyMmFkdmFuY2VkUXVlcnklMjI6JTIyaW1hZ2VzLmNvbnRleHQuaW50ZXJwb2xhdGVkJTIwYW5kJTIwcnVuLmhwYXJhbXMubmFtZSUyMD09JTIwJTVDJTIybWV0ZmFjZXMlNUMlMjIlMjIlN0Q&images=O-JTdCJTIyaW5kZXhEZW5zaXR5JTIyOjcsJTIycmVjb3JkRGVuc2l0eSUyMjoxNSwlMjJ0b29sdGlwJTIyOiU3QiUyMmFwcGVhcmFuY2UlMjI6JTIyYXV0byUyMiwlMjJkaXNwbGF5JTIyOnRydWUsJTIyc2VsZWN0ZWRGaWVsZHMlMjI6JTVCJTVELCUyMnNlbGVjdGVkUGFyYW1zJTIyOiU1QiU1RCU3RCwlMjJhZGRpdGlvbmFsUHJvcGVydGllcyUyMjolN0IlMjJhbGlnbm1lbnRUeXBlJTIyOiUyMkhlaWdodCUyMiwlMjJtZWRpYUl0ZW1TaXplJTIyOjIzLCUyMmltYWdlUmVuZGVyaW5nJTIyOiUyMnBpeGVsYXRlZCUyMiwlMjJzdGFja2luZyUyMjpmYWxzZSU3RCwlMjJmb2N1c2VkU3RhdGUlMjI6JTdCJTIyYWN0aXZlJTIyOmZhbHNlLCUyMmtleSUyMjpudWxsJTdELCUyMnNvcnRGaWVsZHMlMjI6JTVCJTVELCUyMnNvcnRGaWVsZHNEaWN0JTIyOiU3QiU3RCwlMjJpbnB1dHNWYWxpZGF0aW9ucyUyMjolN0IlMjJpbmRleERlbnNpdHklMjI6dHJ1ZSwlMjJyZWNvcmREZW5zaXR5JTIyOnRydWUlN0QsJTIyY2FsY1JhbmdlcyUyMjpmYWxzZSwlMjJzdGVwUmFuZ2UlMjI6JTVCMSw0Njk1NiU1RCwlMjJpbmRleFJhbmdlJTIyOiU1QjAsNyU1RCwlMjJyZWNvcmRTbGljZSUyMjolNUIzMTE0Miw0Njk1NyU1RCwlMjJpbmRleFNsaWNlJTIyOiU1QjAsOCU1RCwlMjJpbWFnZVByb3BlcnRpZXMlMjI6JTdCJTIyYWxpZ25tZW50VHlwZSUyMjolMjJIZWlnaHQlMjIsJTIyaW1hZ2VTaXplJTIyOjI1LCUyMmltYWdlUmVuZGVyaW5nJTIyOiUyMnBpeGVsYXRlZCUyMiU3RCU3RA"> <img src="https://user-images.githubusercontent.com/97726819/225948275-a41946ea-89f4-45f1-bce1-251c84dcddca.png"> </a> |
| Training logs of a neural translation model(from WMT'19 competition). | Training logs of 'lightweight' GAN, proposed in ICLR 2021. |

| [FastSpeech 2 experiments](https://play.aimstack.io/fastspeech2/runs/d9e89aa7875e44b2ba85612a/audios)| [Simple MNIST](https://play.aimstack.io/digit-recognition/runs/7f083da898624a2c98e0f363/distributions) |
| [FastSpeech 2 experiments](https://play.aimstack.io/fastspeech2/runs/d9e89aa7875e44b2ba85612a/audios)| [Simple MNIST](https://play.aimstack.io/digit-recognition/runs/426032ad2d7e4b0385bc6c51/distributions) |
|:---:|:---:|
| <a href="https://play.aimstack.io/fastspeech2/runs/d9e89aa7875e44b2ba85612a/audios"> <img src="https://user-images.githubusercontent.com/97726819/225948457-567526da-a329-4c53-a9a7-98dfe392d4c4.png"> </a> | <a href="https://play.aimstack.io/digit-recognition/runs/7f083da898624a2c98e0f363/distributions"> <img src="https://user-images.githubusercontent.com/97726819/225948599-ff39c5b7-ae7d-4deb-8bc9-5eee1e189d89.png"> </a> |
| Training logs of Microsoft's "FastSpeech 2: Fast and High-Quality End-to-End Text to Speech". | Simple MNIST training logs. |
Expand Down
2 changes: 1 addition & 1 deletion aim/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.23.0
3.24.0
22 changes: 21 additions & 1 deletion aim/cli/up/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
AIM_ENV_MODE_KEY,
AIM_PROFILER_KEY,
AIM_PROXY_URL,
AIM_READ_ONLY_UI,
AIM_TF_LOGS_PATH_KEY,
AIM_UI_BASE_PATH,
AIM_UI_DEFAULT_HOST,
Expand All @@ -43,7 +44,23 @@
@click.option('--profiler', is_flag=True, default=False)
@click.option('--log-level', required=False, default='', type=str)
@click.option('-y', '--yes', is_flag=True, help='Automatically confirm prompt')
def up(dev, host, port, workers, uds, repo, tf_logs, ssl_keyfile, ssl_certfile, base_path, profiler, log_level, yes):
@click.option('--read-only', is_flag=True, default=False)
def up(
dev,
host,
port,
workers,
uds,
repo,
tf_logs,
ssl_keyfile,
ssl_certfile,
base_path,
profiler,
log_level,
yes,
read_only,
):
if dev:
os.environ[AIM_ENV_MODE_KEY] = 'dev'
log_level = log_level or 'debug'
Expand Down Expand Up @@ -72,6 +89,9 @@ def up(dev, host, port, workers, uds, repo, tf_logs, ssl_keyfile, ssl_certfile,
if tf_logs:
os.environ[AIM_TF_LOGS_PATH_KEY] = tf_logs

if read_only:
os.environ[AIM_READ_ONLY_UI] = '1'

try:
db_cmd = build_db_upgrade_command()
exec_cmd(db_cmd, stream_output=True)
Expand Down
2 changes: 1 addition & 1 deletion aim/sdk/index_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def index(
).subtree('meta')
meta_run_tree = meta_tree.subtree('chunks').subtree(run_hash)
meta_run_tree.finalize(index=index)
if meta_run_tree['end_time'] is None:
if meta_run_tree.get('end_time') is None:
index['meta', 'chunks', run_hash, 'end_time'] = datetime.datetime.now(pytz.utc).timestamp()
except (aimrocks.errors.RocksIOError, aimrocks.errors.Corruption):
logger.warning(f"Indexing thread detected corrupted run '{run_hash}'. Skipping.")
Expand Down
16 changes: 15 additions & 1 deletion aim/storage/containertreeview.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Iterator, Tuple, Union
from typing import Any, Iterator, List, Tuple, Union

from aim.storage import encoding as E
from aim.storage import treeutils
Expand Down Expand Up @@ -115,6 +115,20 @@ def items(self, path: Union[AimObjectKey, AimObjectPath] = ()) -> Iterator[Tuple
(key,) = path
yield key, value

def update(
self,
path: Union[AimObjectKey, AimObjectPath],
values: List[Tuple[Union[AimObjectPath, AimObjectKey], AimObject]],
) -> None:
if path == Ellipsis:
path = ()
if isinstance(path, list):
path = tuple(path)
if not isinstance(path, tuple):
path = (path,)
for key, value in values:
self.set(path + (key,), value)

def iterlevel(
self, path: Union[AimObjectKey, AimObjectPath] = (), level: int = 1
) -> Iterator[Tuple[AimObjectPath, AimObject]]:
Expand Down
3 changes: 3 additions & 0 deletions aim/storage/treearrayview.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ def values(self) -> Iterator[Any]:
def items(self) -> Iterator[Tuple[int, Any]]:
yield from self.tree.items()

def update(self, values: List[Tuple[int, Any]]):
self.tree.update((), values)

def __len__(self) -> int:
# TODO lazier
try:
Expand Down
14 changes: 14 additions & 0 deletions aim/storage/treeviewproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ def items_eager(self, path: Union[AimObjectKey, AimObjectPath] = ()) -> List[Tup
def items(self, path: Union[AimObjectKey, AimObjectPath] = ()) -> Iterator[Tuple[AimObjectKey, AimObject]]:
return self.items_eager(path)

def update(
self,
path: Union[AimObjectKey, AimObjectPath],
values: List[Tuple[Union[AimObjectKey, AimObjectPath], AimObject]],
) -> None:
self._rpc_client.run_instruction(self._hash, self._handler, 'update', (path, values), is_write_only=True)

def iterlevel(
self, path: Union[AimObjectKey, AimObjectPath] = (), level: int = 1
) -> Iterator[Tuple[AimObjectPath, AimObject]]:
Expand Down Expand Up @@ -163,6 +170,13 @@ def keys(
def items(self, path: Union[AimObjectKey, AimObjectPath] = ()) -> Iterator[Tuple[AimObjectKey, AimObject]]:
return self.tree.items(self.absolute_path(path))

def update(
self,
path: Union[AimObjectKey, AimObjectPath],
values: List[Tuple[Union[AimObjectPath, AimObjectKey], AimObject]],
):
self.tree.update(self.absolute_path(path), values)

def iterlevel(
self, path: Union[AimObjectKey, AimObjectPath] = (), level: int = 1
) -> Iterator[Tuple[AimObjectPath, AimObject]]:
Expand Down
2 changes: 1 addition & 1 deletion aim/storage/union.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class ItemsIterator(ContainerItemsIterator):
for prefix, iterator in self._iterators.items():
try:
iterator.seek_to_first()
except (aimrocks.errorsRocksIOError, aimrocks.errors.Corruption):
except (aimrocks.errors.RocksIOError, aimrocks.errors.Corruption):
logger.debug(f'Detected corrupted db chunk \'{prefix}\'.')
corrupted_dbs.add(prefix)
self._corrupted_dbs.update(corrupted_dbs)
Expand Down
3 changes: 3 additions & 0 deletions aim/web/api/experiments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from aim.web.api.runs.utils import get_project_repo
from aim.web.api.utils import (
APIRouter, # wrapper for fastapi.APIRouter # wrapper for fastapi.APIRouter
check_read_only,
object_factory,
)
from fastapi import Depends, Header, HTTPException, Request
Expand Down Expand Up @@ -83,6 +84,7 @@ async def get_experiment_api(exp_id: str, factory=Depends(object_factory)):


@experiment_router.delete('/{exp_id}/')
@check_read_only
async def delete_experiment_api(exp_id: str):
repo = get_project_repo()
success = repo.delete_experiment(exp_id)
Expand All @@ -93,6 +95,7 @@ async def delete_experiment_api(exp_id: str):


@experiment_router.put('/{exp_id}/', response_model=ExperimentUpdateOut)
@check_read_only
async def update_experiment_properties_api(exp_id: str, exp_in: ExperimentUpdateIn, factory=Depends(object_factory)):
exp = factory.find_experiment(exp_id)
if not exp:
Expand Down
5 changes: 5 additions & 0 deletions aim/web/api/runs/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
)
from aim.web.api.utils import (
APIRouter, # wrapper for fastapi.APIRouter
check_read_only,
object_factory,
)
from fastapi import Depends, Header, HTTPException, Query
Expand Down Expand Up @@ -180,6 +181,7 @@ async def run_metric_batch_api(run_id: str, requested_traces: RunTracesBatchApiI


@runs_router.put('/{run_id}/', response_model=StructuredRunUpdateOut)
@check_read_only
async def update_run_properties_api(run_id: str, run_in: StructuredRunUpdateIn, factory=Depends(object_factory)):
with factory:
run = factory.find_run(run_id)
Expand Down Expand Up @@ -223,6 +225,7 @@ async def remove_run_tag_api(run_id: str, tag_id: str, factory=Depends(object_fa


@runs_router.delete('/{run_id}/')
@check_read_only
async def delete_run_api(run_id: str):
repo = get_project_repo()
success = repo.delete_run(run_id)
Expand All @@ -235,6 +238,7 @@ async def delete_run_api(run_id: str):


@runs_router.post('/delete-batch/')
@check_read_only
async def delete_runs_batch_api(runs_batch: RunsBatchIn):
repo = get_project_repo()
success, remaining_runs = repo.delete_runs(runs_batch)
Expand All @@ -248,6 +252,7 @@ async def delete_runs_batch_api(runs_batch: RunsBatchIn):


@runs_router.post('/archive-batch/', response_model=StructuredRunsArchivedOut)
@check_read_only
async def archive_runs_batch_api(
runs_batch: RunsBatchIn, archive: Optional[bool] = True, factory=Depends(object_factory)
):
Expand Down
13 changes: 13 additions & 0 deletions aim/web/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import datetime
import os

from functools import wraps
from typing import Any, Callable

import pytz

from aim.web.configs import AIM_READ_ONLY_UI
from fastapi import APIRouter as FastAPIRouter
from fastapi import HTTPException
from fastapi.types import DecoratedCallable
Expand All @@ -24,6 +27,16 @@ def datetime_now():
return datetime.datetime.utcnow().replace(tzinfo=pytz.utc)


def check_read_only(func):
@wraps(func)
async def wrapper(*args, **kwargs):
if os.environ.get(AIM_READ_ONLY_UI):
raise HTTPException(status_code=403)
return await func(*args, **kwargs)

return wrapper


class APIRouter(FastAPIRouter):
def api_route(
self, path: str, *, include_in_schema: bool = True, **kwargs: Any
Expand Down
1 change: 1 addition & 0 deletions aim/web/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
AIM_PROFILER_KEY = '__AIM_PROFILER_ENABLED__'
AIM_PROGRESS_REPORT_INTERVAL = 0.5
AIM_PROJECT_SETTINGS_FILE = '.project_settings'
AIM_READ_ONLY_UI = '__AIM_READ_ONLY_UI__'
2 changes: 1 addition & 1 deletion aim/web/ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ui_v2",
"version": "3.23.0",
"version": "3.24.0",
"private": true,
"dependencies": {
"@aksel/structjs": "^1.0.0",
Expand Down
2 changes: 0 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ sphinx_rtd_theme
m2r2==0.3.3.post2
sphinx-copybutton
Cython==3.0.10

-r ./../requirements.txt
2 changes: 2 additions & 0 deletions docs/source/overview.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Overview

<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=0df03530-c22f-47c2-9db5-b0b923dde002" />

<div align="center">
<img src="https://user-images.githubusercontent.com/13848158/154338760-edfe1885-06f3-4e02-87fe-4b13a403516b.png">
<h3>An easy-to-use & supercharged open-source experiment tracker</h3>
Expand Down
10 changes: 5 additions & 5 deletions docs/source/refs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ $ aim up [ARGS]

| Args | Description |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `-h` &#124; `--host <host>` | Specify host address. |
| `-p` &#124; `--port <port>` | Specify port to listen to. |
| `-h, --host <host>` | Specify host address. |
| `-p, --port <port>` | Specify port to listen to. _Default is 43800._ |
| `--repo <repo_path>` | Path to parent directory of `.aim` repo. _Current working directory by default_. |
| `--dev` | Run UI in development mode. |
| `--dev` | Run UI in development mode—enables hot-reloading only, _not meant for end-users_. |
| `--profiler` | Enables API profiling which logs run trace inside `.aim/profiler` directory. |
| `--log-level` | Specifies log level for python logging package. _`WARNING` by default, `DEBUG` when `--dev` option is provided_. |

Expand All @@ -71,8 +71,8 @@ $ aim server [ARGS]
| Args | Description |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `--repo <repo_path>` | Path to parent directory of `.aim` repo. _Current working directory by default_. |
| `-h` &#124; `--host <host>` | Specify host address. |
| `-p` &#124; `--port <port>` | Specify port to listen to. _Default is 53800_. |
| `-h, --host <host>` | Specify host address. |
| `-p, --port <port>` | Specify port to listen to. _Default is 53800_. |
| `--ssl-keyfile` | Specify path to keyfile for secure connection. |
| `--ssl-certfile` | Specify path to cert. file for secure connection. |
| `--dev` | Run UI in development mode. |
Expand Down

0 comments on commit 7b56361

Please sign in to comment.