Repository: Project-MONAI/MONAI

Issue:
B008 Do not perform function calls in argument defaults
**Describe the bug**
> B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.

**To Reproduce**

Steps to reproduce the behavior:
1. Remove [B008 from the ignore list in setup.cfg](https://github.com/Project-MONAI/MONAI/blob/master/setup.cfg#L47)
2. Run ``./runtests.sh --flake8``

```bash
/home/user/MONAI/monai/apps/datasets.py:61:41: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/monai/apps/datasets.py:211:41: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/monai/engines/evaluator.py:122:28: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/monai/engines/trainer.py:86:28: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_classification_2d.py:46:72: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_classification_2d.py:128:57: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_determinism.py:25:53: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_segmentation_3d.py:44:40: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_segmentation_3d.py:166:41: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_sliding_window.py:33:65: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_unet_2d.py:24:53: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_workflows.py:55:40: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
/home/user/MONAI/tests/test_integration_workflows.py:166:53: B008 Do not perform function calls in argument defaults.  The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call.  If this is intended, assign the function call to a module-level variable and use that variable as a default value.
```

**Environment**
- OS: Ubuntu 18.04
- Python version: 3.7.5
- MONAI version: 8516865

```bash
MONAI version: 0.2.0+28.g8516865
Python version: 3.7.5 (default, Nov  7 2019, 10:50:52)  [GCC 8.3.0]
Numpy version: 1.19.0
Pytorch version: 1.5.1

Optional dependencies:
Pytorch Ignite version: 0.3.0
Nibabel version: 3.1.1
scikit-image version: 0.17.2
Pillow version: 7.2.0
Tensorboard version: 2.2.2
```


Discussion:

Resolving patch:
diff --git a/monai/apps/datasets.py b/monai/apps/datasets.py
--- a/monai/apps/datasets.py
+++ b/monai/apps/datasets.py
@@ -66,7 +66,7 @@ def __init__(
         self,
         root_dir: str,
         section: str,
-        transform: Union[Sequence[Callable], Callable] = LoadPNGd("image"),
+        transform: Union[Sequence[Callable], Callable] = (),
         download: bool = False,
         seed: int = 0,
         val_frac: float = 0.1,
@@ -91,6 +91,8 @@ def __init__(
                 f"Cannot find dataset directory: {dataset_dir}, please use download=True to download it."
             )
         data = self._generate_data_list(dataset_dir)
+        if transform == ():
+            transform = LoadPNGd("image")
         super().__init__(data, transform, cache_num=cache_num, cache_rate=cache_rate, num_workers=num_workers)
 
     def randomize(self, data: Optional[Any] = None) -> None:
@@ -226,7 +228,7 @@ def __init__(
         root_dir: str,
         task: str,
         section: str,
-        transform: Union[Sequence[Callable], Callable] = LoadNiftid(["image", "label"]),
+        transform: Union[Sequence[Callable], Callable] = (),
         download: bool = False,
         seed: int = 0,
         val_frac: float = 0.2,
@@ -265,6 +267,8 @@ def __init__(
             "numTest",
         ]
         self._properties = load_decathlon_properties(os.path.join(dataset_dir, "dataset.json"), property_keys)
+        if transform == ():
+            transform = LoadNiftid(["image", "label"])
         super().__init__(data, transform, cache_num=cache_num, cache_rate=cache_rate, num_workers=num_workers)
 
     def get_indices(self) -> np.ndarray:
diff --git a/monai/engines/evaluator.py b/monai/engines/evaluator.py
--- a/monai/engines/evaluator.py
+++ b/monai/engines/evaluator.py
@@ -130,7 +130,7 @@ def __init__(
         epoch_length: Optional[int] = None,
         prepare_batch: Callable = default_prepare_batch,
         iteration_update: Optional[Callable] = None,
-        inferer: Inferer = SimpleInferer(),
+        inferer: Optional[Inferer] = None,
         post_transform: Optional[Transform] = None,
         key_val_metric: Optional[Dict[str, Metric]] = None,
         additional_metrics: Optional[Dict[str, Metric]] = None,
@@ -151,7 +151,7 @@ def __init__(
         )
 
         self.network = network
-        self.inferer = inferer
+        self.inferer = SimpleInferer() if inferer is None else inferer
 
     def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]:
         """
@@ -225,7 +225,7 @@ def __init__(
         epoch_length: Optional[int] = None,
         prepare_batch: Callable = default_prepare_batch,
         iteration_update: Optional[Callable] = None,
-        inferer: Inferer = SimpleInferer(),
+        inferer: Optional[Inferer] = None,
         post_transform: Optional[Transform] = None,
         key_val_metric: Optional[Dict[str, Metric]] = None,
         additional_metrics: Optional[Dict[str, Metric]] = None,
@@ -247,7 +247,7 @@ def __init__(
 
         self.networks = ensure_tuple(networks)
         self.pred_keys = ensure_tuple(pred_keys)
-        self.inferer = inferer
+        self.inferer = SimpleInferer() if inferer is None else inferer
 
     def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]:
         """
diff --git a/monai/engines/trainer.py b/monai/engines/trainer.py
--- a/monai/engines/trainer.py
+++ b/monai/engines/trainer.py
@@ -88,7 +88,7 @@ def __init__(
         epoch_length: Optional[int] = None,
         prepare_batch: Callable = default_prepare_batch,
         iteration_update: Optional[Callable] = None,
-        inferer: Inferer = SimpleInferer(),
+        inferer: Optional[Inferer] = None,
         post_transform: Optional[Transform] = None,
         key_train_metric: Optional[Dict[str, Metric]] = None,
         additional_metrics: Optional[Dict[str, Metric]] = None,
@@ -113,7 +113,7 @@ def __init__(
         self.network = network
         self.optimizer = optimizer
         self.loss_function = loss_function
-        self.inferer = inferer
+        self.inferer = SimpleInferer() if inferer is None else inferer
 
     def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]):
         """
@@ -211,8 +211,8 @@ def __init__(
         d_optimizer: Optimizer,
         d_loss_function: Callable,
         epoch_length: Optional[int] = None,
-        g_inferer: Inferer = SimpleInferer(),
-        d_inferer: Inferer = SimpleInferer(),
+        g_inferer: Optional[Inferer] = None,
+        d_inferer: Optional[Inferer] = None,
         d_train_steps: int = 1,
         latent_shape: int = 64,
         d_prepare_batch: Callable = default_prepare_batch,
@@ -240,11 +240,11 @@ def __init__(
         self.g_network = g_network
         self.g_optimizer = g_optimizer
         self.g_loss_function = g_loss_function
-        self.g_inferer = g_inferer
+        self.g_inferer = SimpleInferer() if g_inferer is None else g_inferer
         self.d_network = d_network
         self.d_optimizer = d_optimizer
         self.d_loss_function = d_loss_function
-        self.d_inferer = d_inferer
+        self.d_inferer = SimpleInferer() if d_inferer is None else d_inferer
         self.d_train_steps = d_train_steps
         self.latent_shape = latent_shape
         self.g_prepare_batch = g_prepare_batch


Test patch:
diff --git a/tests/test_integration_classification_2d.py b/tests/test_integration_classification_2d.py
--- a/tests/test_integration_classification_2d.py
+++ b/tests/test_integration_classification_2d.py
@@ -43,7 +43,7 @@ def __getitem__(self, index):
         return self.transforms(self.image_files[index]), self.labels[index]
 
 
-def run_training_test(root_dir, train_x, train_y, val_x, val_y, device=torch.device("cuda:0")):
+def run_training_test(root_dir, train_x, train_y, val_x, val_y, device="cuda:0"):
 
     monai.config.print_config()
     # define transforms for image and classification
@@ -125,7 +125,7 @@ def run_training_test(root_dir, train_x, train_y, val_x, val_y, device=torch.dev
     return epoch_loss_values, best_metric, best_metric_epoch
 
 
-def run_inference_test(root_dir, test_x, test_y, device=torch.device("cuda:0")):
+def run_inference_test(root_dir, test_x, test_y, device="cuda:0"):
     # define transforms for image and classification
     val_transforms = Compose([LoadPNG(image_only=True), AddChannel(), ScaleIntensity(), ToTensor()])
     val_ds = MedNISTDataset(test_x, test_y, val_transforms)
diff --git a/tests/test_integration_determinism.py b/tests/test_integration_determinism.py
--- a/tests/test_integration_determinism.py
+++ b/tests/test_integration_determinism.py
@@ -22,7 +22,7 @@
 from monai.utils import set_determinism
 
 
-def run_test(batch_size=64, train_steps=200, device=torch.device("cuda:0")):
+def run_test(batch_size=64, train_steps=200, device="cuda:0"):
     class _TestBatch(Dataset):
         def __init__(self, transforms):
             self.transforms = transforms
diff --git a/tests/test_integration_segmentation_3d.py b/tests/test_integration_segmentation_3d.py
--- a/tests/test_integration_segmentation_3d.py
+++ b/tests/test_integration_segmentation_3d.py
@@ -40,7 +40,7 @@
 from tests.utils import skip_if_quick
 
 
-def run_training_test(root_dir, device=torch.device("cuda:0"), cachedataset=False):
+def run_training_test(root_dir, device="cuda:0", cachedataset=False):
     monai.config.print_config()
     images = sorted(glob(os.path.join(root_dir, "img*.nii.gz")))
     segs = sorted(glob(os.path.join(root_dir, "seg*.nii.gz")))
@@ -166,7 +166,7 @@ def run_training_test(root_dir, device=torch.device("cuda:0"), cachedataset=Fals
     return epoch_loss_values, best_metric, best_metric_epoch
 
 
-def run_inference_test(root_dir, device=torch.device("cuda:0")):
+def run_inference_test(root_dir, device="cuda:0"):
     images = sorted(glob(os.path.join(root_dir, "im*.nii.gz")))
     segs = sorted(glob(os.path.join(root_dir, "seg*.nii.gz")))
     val_files = [{"img": img, "seg": seg} for img, seg in zip(images, segs)]
diff --git a/tests/test_integration_sliding_window.py b/tests/test_integration_sliding_window.py
--- a/tests/test_integration_sliding_window.py
+++ b/tests/test_integration_sliding_window.py
@@ -29,7 +29,7 @@
 from tests.utils import make_nifti_image
 
 
-def run_test(batch_size, img_name, seg_name, output_dir, device=torch.device("cuda:0")):
+def run_test(batch_size, img_name, seg_name, output_dir, device="cuda:0"):
     ds = NiftiDataset([img_name], [seg_name], transform=AddChannel(), seg_transform=AddChannel(), image_only=False)
     loader = DataLoader(ds, batch_size=1, pin_memory=torch.cuda.is_available())
 
diff --git a/tests/test_integration_unet_2d.py b/tests/test_integration_unet_2d.py
--- a/tests/test_integration_unet_2d.py
+++ b/tests/test_integration_unet_2d.py
@@ -21,7 +21,7 @@
 from monai.networks.nets import BasicUNet, UNet
 
 
-def run_test(net_name="basicunet", batch_size=64, train_steps=100, device=torch.device("cuda:0")):
+def run_test(net_name="basicunet", batch_size=64, train_steps=100, device="cuda:0"):
     class _TestBatch(Dataset):
         def __getitem__(self, _unused_id):
             im, seg = create_test_image_2d(128, 128, noise_max=1, num_objs=4, num_seg_classes=1)
diff --git a/tests/test_integration_workflows.py b/tests/test_integration_workflows.py
--- a/tests/test_integration_workflows.py
+++ b/tests/test_integration_workflows.py
@@ -53,7 +53,7 @@
 from tests.utils import skip_if_quick
 
 
-def run_training_test(root_dir, device=torch.device("cuda:0"), amp=False):
+def run_training_test(root_dir, device="cuda:0", amp=False):
     images = sorted(glob(os.path.join(root_dir, "img*.nii.gz")))
     segs = sorted(glob(os.path.join(root_dir, "seg*.nii.gz")))
     train_files = [{"image": img, "label": seg} for img, seg in zip(images[:20], segs[:20])]
@@ -165,7 +165,7 @@ def run_training_test(root_dir, device=torch.device("cuda:0"), amp=False):
     return evaluator.state.best_metric
 
 
-def run_inference_test(root_dir, model_file, device=torch.device("cuda:0"), amp=False):
+def run_inference_test(root_dir, model_file, device="cuda:0", amp=False):
     images = sorted(glob(os.path.join(root_dir, "im*.nii.gz")))
     segs = sorted(glob(os.path.join(root_dir, "seg*.nii.gz")))
     val_files = [{"image": img, "label": seg} for img, seg in zip(images, segs)]
diff --git a/tests/test_integration_workflows_gan.py b/tests/test_integration_workflows_gan.py
--- a/tests/test_integration_workflows_gan.py
+++ b/tests/test_integration_workflows_gan.py
@@ -33,7 +33,7 @@
 from tests.utils import skip_if_quick
 
 
-def run_training_test(root_dir, device=torch.device("cuda:0")):
+def run_training_test(root_dir, device="cuda:0"):
     real_images = sorted(glob(os.path.join(root_dir, "img*.nii.gz")))
     train_files = [{"reals": img} for img in zip(real_images)]