MNT: Fix incorrect type annotations (#846)

ENH: Refactor Swin Transformer checkpointing (#843)

Refactor Swin Transformer checkpointing to enable patch embedding
checkpointing overriding without duplication the whole custom forward

MNT: Fix incorrect type annotations (#846)

ENH: Refactor Swin Transformer checkpointing (#843)

Refactor Swin Transformer checkpointing to enable patch embedding
checkpointing overriding without duplication the whole custom forward

Add multi-modal to root makefile

πŸ› Fix Makefile updates

πŸ“ Update dev documentation

πŸ”§ Add pyproject.toml

πŸ‘· Update makefiles to use black config

πŸ“ Add VS Code + black docs

πŸ”§ Update settings.json for all repos
This commit is contained in:
Peter Hessey 2023-03-21 09:21:09 +00:00
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ 45235164a7
ΠšΠΎΠΌΠΌΠΈΡ‚ c7c5b03a74
31 ΠΈΠ·ΠΌΠ΅Π½Ρ‘Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²: 180 Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΉ ΠΈ 78 ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΉ

2
.git-blame-ignore-revs Normal file
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -0,0 +1,2 @@
# black styling refactor
hashgoeshere

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -49,8 +49,9 @@ repos:
files: ^hi-ml-multimodal/
args: [--config, hi-ml-multimodal/.flake8]
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v2.0.2
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: autopep8
args: [--in-place, --max-line-length, "120"]
- id: black
extend-exclude: ^docs/source/amulet/amulet_script.py
args: [--line-length, "120", --skip-string-normalization]

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -8,8 +8,15 @@ env:
# call make for each sub package
define call_packages
cd hi-ml-azure && $(MAKE) $(1)
cd hi-ml && $(MAKE) $(1)
cd hi-ml-azure && $(MAKE) $(1)
cd hi-ml-cpath && $(MAKE) $(1)
cd hi-ml-multimodal && $(MAKE) $(1)
endef
define call_pip_packages
cd hi-ml && $(MAKE) $(1)
cd hi-ml-azure && $(MAKE) $(1)
endef
## Package management
@ -28,7 +35,7 @@ pip_test: pip_upgrade
# pip install local packages in editable mode for development and testing
call_pip_local:
$(call call_packages,call_pip_local)
$(call call_pip_packages,call_pip_local)
# pip upgrade and install local packages in editable mode
pip_local: pip_upgrade call_pip_local
@ -55,7 +62,7 @@ clean:
# build package, assuming build requirements already installed
call_build:
$(call call_packages,call_build)
$(call call_pip_packages,call_build)
# pip install build requirements and build package
build: pip_build call_build
@ -68,6 +75,10 @@ flake8:
mypy:
$(call call_packages,mypy)
# run black styling, assuming test requirements already installed
black:
$(call call_packages,black)
# run pyright, assuming test requirements already installed
call_pyright:
npm install -g pyright
@ -77,7 +88,7 @@ call_pyright:
pyright: conda call_pyright
# run basic checks, assuming test requirements already installed
check: flake8 mypy
check: flake8 mypy black
# run pytest on package, assuming test requirements already installed
pytest:
@ -85,11 +96,11 @@ pytest:
# run pytest fast subset on package, assuming test requirements already installed
pytest_fast:
$(call call_packages,pytest_fast)
$(call call_pip_packages,pytest_fast)
# run pytest with coverage on package, and format coverage output as a text file, assuming test requirements already installed
call_pytest_and_coverage:
$(call call_packages,call_pytest_and_coverage)
$(call call_pip_packages,call_pytest_and_coverage)
# install test requirements and run pytest coverage
pytest_and_coverage: pip_test call_pytest_and_coverage

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,6 @@
# Microsoft Health Intelligence Machine Learning Toolbox
[![Codecov coverage](https://codecov.io/gh/microsoft/hi-ml/branch/main/graph/badge.svg?token=kMr2pSIJ2U)](https://codecov.io/gh/microsoft/hi-ml)
[![Codecov coverage](https://codecov.io/gh/microsoft/hi-ml/branch/main/graph/badge.svg?token=kMr2pSIJ2U)](https://codecov.io/gh/microsoft/hi-ml) [![Code style: black](https://camo.githubusercontent.com/d91ed7ac7abbd5a6102cbe988dd8e9ac21bde0a73d97be7603b891ad08ce3479/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d626c61636b2d3030303030302e737667)](https://github.com/psf/black)
## Overview

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -35,15 +35,47 @@ Please follow the general [PEP 8](https://peps.python.org/pep-0008/) Python rule
To improve readability, functions or methods that return boolean values should follow a `is_...`, `has_...`, `use...` pattern, like `is_status_ok` instead of `ok`.
### Static Analysis and Linting
### Static Analysis, Linting and Styling
We use `flake8` as a linter, `mypy` and pyright for static typechecking, and `black` for styling. All these tools run as part of the PR workflow, and must run without errors for a contribution to be accepted.
We use `flake8` as a linter, and `mypy` and pyright for static typechecking. Both tools run as part of the PR workflow, and must run without errors for a contribution to be accepted.
`mypy` requires that all functions and methods carry type annotations.
See the [`mypy` documentation](https://mypy.readthedocs.io/en/latest/getting_started.html#function-signatures-and-dynamic-vs-static-typing) for more information.
We highly recommend to run all those tools _before_ pushing the latest changes to a PR.
If you have `make` installed, you can run both tools in one go via `make check` (from the repository root folder).
### Black styling
We use `black` for styling all of our code. To pass the tests carried out in `make check` (or `make black`) you can run the following command to reformat your changed file as per our guidelines:
```shell
black <path_to_python_file>
```
You can also run `black` on the whole repository by running the following command from the head of the repo:
```shell
black .
```
#### Black VS Code Integration
If you're using VS Code as your IDE, you can avoid having to call `black` every time you want to style some files by installing the [`black` formatter extension](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter) and adding the following to your vscode `settings.json` file:
```json
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
},
```
Now every time you save a file it will automatically be formatted by `black`.
#### Black pre-commit hook
If you do not style your code yourself, then the pre-commit hook on your PR will attempt to do this automatically. Please be aware that this may cause conflicts if you're working on an open pull request. We highly recommend styling your code before submitting!
### Documentation
For general information around docstrings, please check [PEP 257](https://peps.python.org/pep-0257/).

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -91,7 +91,7 @@ dependencies:
The repository contains a makefile with definitions for common operations.
* `make check`: Run `flake8` and `mypy` on the repository.
* `make check`: Run `flake8`, `mypy` and `black` on the repository.
* `make test`: Run `flake8` and `mypy` on the repository, then all tests via `pytest`
* `make pip`: Install all packages for running and testing in the current interpreter.
* `make conda`: Update the hi-ml Conda environment and activate it

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,9 @@
[flake8]
max-line-length = 120
max-complexity = 25
select = B950
extend-ignore =
E731,
W503,
E203,
E501,

4
hi-ml-azure/.vscode/settings.json поставляСмый
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -47,7 +47,9 @@
"[python]": {
"editor.rulers": [
120
]
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
},
// The settings below are specific to this project,
// and may override settings in the workspace configuration.

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -55,8 +55,12 @@ mypy:
mypy --install-types --show-error-codes --non-interactive --package health_azure
mypy --install-types --show-error-codes --non-interactive --package testazure
# run black check
black:
black . --check --diff
# run basic checks, assuming test requirements already installed
check: flake8 mypy
check: flake8 mypy black
# run pytest on package, assuming test requirements already installed
pytest:

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,7 +1,7 @@
import logging
import os
import pytest
from _pytest.capture import SysCapture
from pytest import CaptureFixture, LogCaptureFixture
from time import sleep
from health_azure.logging import format_time_from_seconds, elapsed_timer, print_message_with_rank_pid, logging_section
from health_azure.utils import ENV_LOCAL_RANK
@ -26,7 +26,7 @@ def test_format_time_from_second() -> None:
@pytest.mark.parametrize("level", ['DEBUG', 'INFO'])
def test_print_message_with_rank_pid(level: str, capsys: SysCapture) -> None:
def test_print_message_with_rank_pid(level: str, capsys: CaptureFixture) -> None:
rank = "0"
os.environ[ENV_LOCAL_RANK] = rank
message = "test"
@ -39,16 +39,16 @@ def test_print_message_with_rank_pid(level: str, capsys: SysCapture) -> None:
@pytest.mark.parametrize("format_seconds", [True, False])
def test_elapsed_timer(format_seconds: bool, capsys: SysCapture) -> None:
def test_elapsed_timer(format_seconds: bool, capsys: CaptureFixture) -> None:
rank = "0"
os.environ[ENV_LOCAL_RANK] = rank
with elapsed_timer("test", format_seconds):
sleep(0.1) # Sleep for 100 ms
stdout: str = capsys.readouterr().out # type: ignore
stdout: str = capsys.readouterr().out
assert "0.10 seconds" in stdout
def test_logging_section(caplog: pytest.LogCaptureFixture) -> None:
def test_logging_section(caplog: LogCaptureFixture) -> None:
rank = "0"
os.environ[ENV_LOCAL_RANK] = rank
with logging_section("test"):

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,9 @@
[flake8]
max-line-length = 120
max-complexity = 25
select = B950
extend-ignore =
E731,
W503,
E203,
E501,

4
hi-ml-cpath/.vscode/settings.json поставляСмый
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -47,7 +47,9 @@
"[python]": {
"editor.rulers": [
120
]
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
},
// The settings below are specific to this project,
// and may override settings in the workspace configuration.

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -70,8 +70,12 @@ mypy:
mypy --install-types --show-error-codes --non-interactive --package testhisto
mypy --install-types --show-error-codes --non-interactive --package testSSL
# run black check
black:
black . --check --diff
# run basic checks
check: flake8 mypy
check: flake8 mypy black
# run pytest on package, assuming test requirements already installed
pytest:

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -208,6 +208,9 @@ class BaseMIL(LightningContainer, LoadingParams, EncoderParams, PoolingParams, C
random see. See `SlidesDataModule` for an example how to achieve that."""
return None
def get_encoder_params(self) -> EncoderParams:
return create_from_matching_params(self, EncoderParams)
def create_model(self) -> DeepMILModule:
self.data_module = self.get_data_module()
outputs_handler = self.get_outputs_handler()
@ -216,7 +219,7 @@ class BaseMIL(LightningContainer, LoadingParams, EncoderParams, PoolingParams, C
class_names=self.class_names,
class_weights=self.data_module.class_weights,
outputs_folder=self.outputs_folder,
encoder_params=create_from_matching_params(self, EncoderParams),
encoder_params=self.get_encoder_params(),
pooling_params=create_from_matching_params(self, PoolingParams),
classifier_params=create_from_matching_params(self, ClassifierParams),
optimizer_params=create_from_matching_params(self, OptimizerParams),

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -327,7 +327,7 @@ class SwinTransformerCheckpointingMixin:
def __init__(
self,
feature_extractor_fn: ResNet,
feature_extractor_fn: SwinTransformer,
checkpoint_segments_size: int = 2,
) -> None:
"""
@ -338,12 +338,20 @@ class SwinTransformerCheckpointingMixin:
self.feature_extractor_fn = feature_extractor_fn
self.checkpoint_segments_size = checkpoint_segments_size
def custom_forward(self, images: torch.Tensor) -> torch.Tensor:
"""Custom forward pass that uses activation checkpointing to save memory."""
# patch embedding checkpointing
def custom_patch_embedding_forward(self, images: torch.Tensor) -> torch.Tensor:
"""Custom patch partitioning checkpointing"""
_, _, H, W = images.shape
img_size = self.feature_extractor_fn.patch_embed.img_size
assert H == img_size[0] and W == img_size[1], \
f"Input image size ({H}*{W}) doesn't match model ({img_size[0]}*{img_size[1]})."
images = checkpoint(self.feature_extractor_fn.patch_embed.proj, images)
images = images.flatten(2).transpose(1, 2) # BCHW -> BNC
images = checkpoint(self.feature_extractor_fn.patch_embed.norm, images)
return images
def custom_forward(self, images: torch.Tensor) -> torch.Tensor:
"""Custom forward pass that uses activation checkpointing to save memory."""
images = self.custom_patch_embedding_forward(images)
# do not checkpoint dropout
images = self.feature_extractor_fn.pos_drop(images)
# sequential layers checkpointing

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -94,7 +94,6 @@ class EncoderParams(param.Parameterized):
"""Given the current encoder parameters, returns the encoder object.
:param outputs_folder: The output folder where SSL checkpoint should be saved.
:param encoder_params: The encoder arguments that define the encoder class object depending on the encoder type.
:raises ValueError: If the encoder type is not supported.
:return: A TileEncoder instance for deepmil module.
"""

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -8,7 +8,7 @@ from pathlib import Path
import time
from typing import Any, Callable, Dict, Sequence, Union
import numpy as np
from _pytest.capture import SysCapture
from pytest import CaptureFixture
import pytest
import torch
from monai.data.meta_tensor import MetaTensor
@ -376,7 +376,7 @@ def test_metatensor_to_tensor_d_transform() -> None:
_ = transform(new_sample)
def test_timer_wrapper_transform(capsys: SysCapture) -> None:
def test_timer_wrapper_transform(capsys: CaptureFixture) -> None:
sample = {"a": 1, SlideKey.SLIDE_ID: "0"}
class DummyTransform:
@ -387,7 +387,7 @@ def test_timer_wrapper_transform(capsys: SysCapture) -> None:
transform = TimerWrapper(DummyTransform())
out = transform(sample)
assert out == sample
message = capsys.readouterr().out # type: ignore
message = capsys.readouterr().out
assert "Rank " in message
assert "DummyTransform, Slide 0 took 0.10 seconds" in message

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -7,11 +7,12 @@ import shutil
from unittest.mock import MagicMock, patch
import numpy as np
import pytest
from _pytest.capture import SysCapture
from pytest import CaptureFixture
from pathlib import Path
from typing import List, Optional, Tuple
from monai.transforms import LoadImaged
from monai.data.wsi_reader import CuCIMWSIReader, OpenSlideWSIReader, WSIReader
from PIL import Image
from health_cpath.datasets.default_paths import PANDA_DATASET_ID
from health_cpath.datasets.panda_dataset import PandaDataset
from health_cpath.preprocessing.loading import (
@ -20,7 +21,6 @@ from health_cpath.preprocessing.loading import (
from health_cpath.scripts.mount_azure_dataset import mount_dataset
from health_cpath.utils.naming import SlideKey
from health_ml.utils.common_utils import is_gpu_available
from PIL import Image
from testhiml.utils_testhiml import DEFAULT_WORKSPACE
@ -86,7 +86,7 @@ def test_load_slide(tmp_path: Path) -> None:
@pytest.mark.skipif(no_gpu, reason="Test requires GPU")
@pytest.mark.gpu
def test_failed_to_estimate_foreground(
roi_type: ROIType, mock_panda_slides_root_dir: Path, capsys: SysCapture
roi_type: ROIType, mock_panda_slides_root_dir: Path, capsys: CaptureFixture
) -> None:
loading_params = LoadingParams(roi_type=roi_type, level=2)
load_transform: BaseLoadROId = loading_params.get_load_roid_transform() # type: ignore
@ -99,7 +99,7 @@ def test_failed_to_estimate_foreground(
with patch.object(load_transform.reader, "get_data", return_value=(MagicMock(), MagicMock())):
_ = load_transform(sample)
mock_get_wsi_bbox.assert_called_once()
stdout: str = capsys.readouterr().out # type: ignore
stdout: str = capsys.readouterr().out
assert "Failed to estimate bounding box for slide _0: The input mask is empty" in stdout

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,9 @@
[flake8]
max-line-length = 120
max-complexity = 25
select = B950
extend-ignore =
E731,
W503,
E203,
E501,

4
hi-ml-multimodal/.vscode/settings.json поставляСмый
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -47,7 +47,9 @@
"[python]": {
"editor.rulers": [
120
]
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
},
// The settings below are specific to this project,
// and may override settings in the workspace configuration.

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -46,6 +46,10 @@ build:
flake8:
flake8 --count --statistics .
# run black check
black:
black . --check --diff
# run mypy, assuming test requirements already installed
mypy:
mypy --install-types --show-error-codes --non-interactive setup.py
@ -75,7 +79,7 @@ pyright:
pyright
# run basic checks
check: flake8 mypy pyright
check: flake8 mypy pyright black
# bump version from specified part (major, minor or patch) (dry run). Usage:
# $ make bump_version_dry part=patch

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,9 @@
[flake8]
max-line-length = 120
max-complexity = 25
select = B950
extend-ignore =
E731,
W503,
E203,
E501,

4
hi-ml/.vscode/settings.json поставляСмый
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -47,7 +47,9 @@
"[python]": {
"editor.rulers": [
120
]
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
},
// The settings below are specific to this project,
// and may override settings in the workspace configuration.

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -55,8 +55,12 @@ mypy:
mypy --install-types --show-error-codes --non-interactive --package health_ml
mypy --install-types --show-error-codes --non-interactive --package testhiml
# run black check
black:
black . --check --diff
# run basic checks, assuming test requirements already installed
check: flake8 mypy
check: flake8 mypy black
# run pytest on package, assuming test requirements already installed
pytest:

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -28,9 +28,9 @@ dependencies:
- libsqlite=3.40.0=h753d276_0
- libstdcxx-ng=12.2.0=h46fd767_19
- libuv=1.44.2=h166bdaf_0
- libxml2=2.10.3=h7463322_0
- libxml2=2.10.3=hca2bb57_3
- libzlib=1.2.13=h166bdaf_4
- llvm-openmp=15.0.7=h0cdce71_0
- llvm-openmp=16.0.0=h417c0b6_0
- mkl=2022.1.0=h84fe81f_915
- mkl-devel=2022.1.0=ha770c72_916
- mkl-include=2022.1.0=h84fe81f_915
@ -40,22 +40,24 @@ dependencies:
- python=3.7.3
- pytorch-mutex=1.0=cuda
- readline=8.1.2=h0f457ee_0
- setuptools=67.4.0=pyhd8ed1ab_0
- setuptools=67.6.0=pyhd8ed1ab_0
- sqlite=3.40.0=h4ff8645_0
- tbb=2021.8.0=hf52228f_0
- tk=8.6.12=h27826a3_0
- typing_extensions=4.5.0=pyha770c72_0
- xz=5.2.6=h166bdaf_0
- zlib=1.2.13=h166bdaf_4
- zstd=1.5.2=h3eb15da_6
- pip:
- absl-py==1.4.0
- adal==1.2.7
- aiohttp==3.8.4
- aiosignal==1.3.1
- alabaster==0.7.13
- alembic==1.9.4
- alembic==1.10.2
- applicationinsights==0.11.10
- argcomplete==2.0.0
- astroid==2.14.2
- argcomplete==2.1.2
- astroid==2.15.0
- async-timeout==4.0.2
- asynctest==0.13.0
- attrs==22.2.0
@ -67,21 +69,21 @@ dependencies:
- azure-mgmt-authorization==3.0.0
- azure-mgmt-containerregistry==10.1.0
- azure-mgmt-core==1.3.2
- azure-mgmt-keyvault==10.1.0
- azure-mgmt-keyvault==10.2.0
- azure-mgmt-resource==21.2.1
- azure-mgmt-storage==20.1.0
- azure-storage-blob==12.10.0
- azure-storage-file-datalake==12.10.0
- azure-storage-file-share==12.11.0
- azure-storage-file-datalake==12.10.1
- azure-storage-file-share==12.11.1
- azureml-core==1.49.0
- azureml-dataprep==4.9.2
- azureml-dataprep==4.9.5
- azureml-dataprep-native==38.0.0
- azureml-dataprep-rslex==2.16.3
- azureml-dataprep-rslex==2.16.4
- azureml-dataset-runtime==1.49.0
- azureml-mlflow==1.49.0
- azureml-telemetry==1.49.0
- azureml-tensorboard==1.49.0
- azureml-train-core==1.49.0
- azureml-train-core==1.49.0.post1
- azureml-train-restclients-hyperdrive==1.49.0
- babel==2.12.1
- backports-tempfile==1.0
@ -93,16 +95,16 @@ dependencies:
- certifi==2022.12.7
- cffi==1.15.1
- cfgv==3.3.1
- charset-normalizer==3.0.1
- charset-normalizer==3.1.0
- click==8.1.3
- cloudpickle==2.2.1
- colorama==0.4.6
- conda-merge==0.2.0
- contextlib2==21.6.0
- coverage==7.1.0
- cryptography==39.0.1
- cryptography==39.0.2
- cycler==0.11.0
- databricks-cli==0.17.4
- databricks-cli==0.17.5
- dataclasses-json==0.5.2
- dill==0.3.6
- distlib==0.3.6
@ -111,9 +113,10 @@ dependencies:
- docutils==0.16
- dotnetcore2==3.1.23
- entrypoints==0.4
- exceptiongroup==1.1.0
- filelock==3.9.0
- exceptiongroup==1.1.1
- filelock==3.10.0
- flake8==5.0.4
- flake8-bugbear==23.3.12
- flask==2.2.3
- fonttools==4.38.0
- frozenlist==1.3.3
@ -121,14 +124,13 @@ dependencies:
- fusepy==3.0.1
- gitdb==4.0.10
- gitpython==3.1.31
- google-auth==2.16.1
- google-auth==2.16.2
- google-auth-oauthlib==0.4.6
- greenlet==2.0.2
- grpcio==1.51.3
- gunicorn==20.1.0
- hi-ml-azure==0.2.18
- humanfriendly==10.0
- identify==2.5.18
- identify==2.5.21
- idna==3.4
- imagesize==1.4.1
- importlib-metadata==5.2.0
@ -180,13 +182,13 @@ dependencies:
- opencv-python-headless==4.7.0.72
- packaging==21.3
- pandas==1.3.5
- param==1.12.3
- param==1.13.0
- paramiko==2.12.0
- pathspec==0.11.0
- pathspec==0.11.1
- pillow==9.3.0
- pkginfo==1.9.6
- pkgutil-resolve-name==1.3.10
- platformdirs==3.0.0
- platformdirs==3.1.1
- pluggy==1.0.0
- portalocker==2.7.0
- pre-commit==2.21.0
@ -245,9 +247,9 @@ dependencies:
- sphinxcontrib-jsmath==1.0.1
- sphinxcontrib-qthelp==1.0.3
- sphinxcontrib-serializinghtml==1.1.5
- sqlalchemy==1.4.46
- sqlalchemy==1.4.47
- sqlparse==0.4.3
- strictyaml==1.6.2
- strictyaml==1.7.3
- stringcase==1.2.0
- tabulate==0.9.0
- tensorboard==2.11.2
@ -257,15 +259,14 @@ dependencies:
- tomli==2.0.1
- tomlkit==0.11.6
- torch==1.13.1
- torchmetrics==0.11.3
- torchmetrics==0.11.4
- torchvision==0.14.1
- tqdm==4.64.1
- tqdm==4.65.0
- twine==3.3.0
- typed-ast==1.5.4
- typing-extensions==4.5.0
- typing-inspect==0.8.0
- urllib3==1.26.14
- virtualenv==20.20.0
- urllib3==1.26.15
- virtualenv==20.21.0
- webencodings==0.5.1
- websocket-client==1.5.1
- werkzeug==2.2.3

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -380,7 +380,7 @@ def test_runner_help(mock_runner: Runner, capsys: CaptureFixture) -> None:
with pytest.raises(SystemExit):
with patch.object(sys, "argv", arguments):
mock_runner.run()
stdout: str = capsys.readouterr().out # type: ignore
stdout: str = capsys.readouterr().out
# There are at least 3 parameters in ExperimentConfig that should print with defaults
assert stdout.count("(default: ") > 3

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -14,7 +14,7 @@ from unittest.mock import MagicMock, PropertyMock, patch
import pytest
import torch
from _pytest.capture import SysCapture
from pytest import CaptureFixture
from _pytest.logging import LogCaptureFixture
from azureml._restclient.constants import RunStatus
from azureml.core import Run
@ -372,7 +372,7 @@ def test_progress_bar_enable() -> None:
assert bar.is_enabled
def test_progress_bar(capsys: SysCapture) -> None:
def test_progress_bar(capsys: CaptureFixture) -> None:
bar = AzureMLProgressBar(refresh_rate=1)
mock_module = mock.MagicMock(global_step=34)
mock_trainer = mock.MagicMock(current_epoch=12,
@ -386,7 +386,8 @@ def test_progress_bar(capsys: SysCapture) -> None:
assert bar.trainer == mock_trainer
def latest_message() -> str:
return capsys.readouterr().out.splitlines()[-1] # type: ignore
out: str = capsys.readouterr().out
return out.splitlines()[-1]
# Messages in training
bar.on_train_epoch_start(mock_trainer, None) # type: ignore
@ -449,7 +450,7 @@ def test_progress_bar_to_logging(caplog: LogCaptureFixture) -> None:
@pytest.mark.parametrize("print_timestamp", [True, False])
def test_progress_bar_to_stdout(capsys: SysCapture, print_timestamp: bool) -> None:
def test_progress_bar_to_stdout(capsys: CaptureFixture, print_timestamp: bool) -> None:
"""
Check that the progress bar correctly writes to stdout, and that timestamps are generated if requested.
"""
@ -457,7 +458,7 @@ def test_progress_bar_to_stdout(capsys: SysCapture, print_timestamp: bool) -> No
today = datetime.utcnow().strftime("%Y-%m-%d")
to_stdout = AzureMLProgressBar(write_to_logging_info=False, print_timestamp=print_timestamp)
to_stdout._print(message)
stdout: str = capsys.readouterr().out # type: ignore
stdout: str = capsys.readouterr().out
print(f"Output: {stdout}")
assert message in stdout
assert stdout.startswith(today) == print_timestamp

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,9 @@
[flake8]
max-line-length = 120
max-complexity = 25
select = B950
extend-ignore =
E731,
W503,
E203,
E501,

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -24,5 +24,6 @@ Make file commands:
* `make pip_local` to install the package in editable mode. This must happen before running tests.
* `make build` to build the package
* `make mypy` to run `mypy`
* `make check` to run `flake8`, `mypy` and `pyright`
* `make black` to run `black` checks (not reformatting)
* `make check` to run `flake8`, `mypy`, `pyright` and `black`
* `make clean` to clean up all temporary files and folders

4
pyproject.toml Normal file
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -0,0 +1,4 @@
[tool.black]
line-length = 120
skip-string-normalization = true
extend-exclude = "docs/source/amulet/amulet_script.py"

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,6 @@
black==23.1.0
coverage==7.1.0
flake8==5.0.4
flake8-bugbear==23.3.12
mypy==1.0.1
pre-commit==2.21.0
pylint==2.16.2