We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Can't use None (anymore) in checkpoint_callback
## 🐛 Bug
using None in checkpoint_callback now errors out

```
-- Process 0 terminated with the following error:
Traceback (most recent call last):
  File "/opt/conda/lib/python3.6/site-packages/torch/multiprocessing/spawn.py", line 20, in _wrap
    fn(i, *args)
  File "/opt/conda/lib/python3.6/site-packages/pytorch_lightning/trainer/distrib_data_parallel.py", line 562, in ddp_train
    q.put(self.checkpoint_callback.best_model_path)
AttributeError: 'NoneType' object has no attribute 'best_model_path'
```

### To Reproduce
`trainer = Trainer(checkpoint_callback=None)`

Ran into this issue from upgrading to masters, was using masters from a few commits ago before

Edit: `False` casuses the same error as well

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pytorch_lightning/accelerator_backends/ddp_spawn_backend.py`
Content:
```
1 # Copyright The PyTorch Lightning team.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License
14 
15 import os
16 import torch
17 import torch.multiprocessing as mp
18 from pytorch_lightning.utilities.distributed import rank_zero_only
19 from pytorch_lightning import _logger as log
20 
21 try:
22     from apex import amp
23 except ImportError:
24     APEX_AVAILABLE = False
25 else:
26     APEX_AVAILABLE = True
27 
28 
29 class DDPSpawnBackend(object):
30 
31     def __init__(self, trainer):
32         self.trainer = trainer
33         self.mp_queue = None
34 
35     def setup(self):
36         self.trainer.set_random_port()
37 
38         # pass in a state q
39         smp = mp.get_context('spawn')
40         self.mp_queue = smp.SimpleQueue()
41 
42     def train(self, model, nprocs):
43         mp.spawn(self.ddp_train, nprocs=nprocs, args=(self.mp_queue, model,))
44 
45     def teardown(self, model):
46         # restore main state with best weights
47         best_path = self.mp_queue.get()
48         results = self.mp_queue.get()
49         last_path = self.mp_queue.get()
50 
51         # transfer back the best path to the trainer
52         self.trainer.checkpoint_callback.best_model_path = best_path
53         # todo, pass also bets score
54 
55         # load last weights
56         if last_path is not None and not self.trainer.testing:
57             ckpt = torch.load(last_path, map_location=lambda storage, loc: storage)
58             model.load_state_dict(ckpt)
59 
60         self.trainer.model = model
61         return results
62 
63     def ddp_train(self, process_idx, mp_queue, model):
64         """
65         Entry point for ddp
66 
67         Args:
68             process_idx:
69             mp_queue: multiprocessing queue
70             model:
71 
72         Returns:
73 
74         """
75         # show progressbar only on progress_rank 0
76         if (self.trainer.node_rank != 0 or process_idx != 0) and self.trainer.progress_bar_callback is not None:
77             self.trainer.progress_bar_callback.disable()
78 
79         # determine which process we are and world size
80         if self.trainer.use_ddp:
81             self.trainer.local_rank = process_idx
82             self.trainer.global_rank = self.trainer.node_rank * self.trainer.num_processes + process_idx
83             self.trainer.world_size = self.trainer.num_nodes * self.trainer.num_processes
84 
85         elif self.trainer.use_ddp2:
86             self.trainer.local_rank = self.trainer.node_rank
87             self.trainer.global_rank = self.trainer.node_rank
88             self.trainer.world_size = self.trainer.num_nodes
89 
90         # set warning rank
91         rank_zero_only.rank = self.trainer.global_rank
92 
93         # set up server using proc 0's ip address
94         # try to init for 20 times at max in case ports are taken
95         # where to store ip_table
96         model.trainer = self.trainer
97         model.init_ddp_connection(
98             self.trainer.global_rank,
99             self.trainer.world_size,
100             self.trainer.is_slurm_managing_tasks
101         )
102 
103         # call setup after the ddp process has connected
104         self.trainer.call_setup_hook(model)
105 
106         # on world_size=0 let everyone know training is starting
107         if self.trainer.is_global_zero:
108             log.info('-' * 100)
109             log.info(f'distributed_backend={self.trainer.distributed_backend}')
110             log.info(f'All DDP processes registered. Starting ddp with {self.trainer.world_size} processes')
111             log.info('-' * 100)
112 
113         # CHOOSE OPTIMIZER
114         # allow for lr schedulers as well
115         optimizers, lr_schedulers, optimizer_frequencies = self.trainer.init_optimizers(model)
116         self.trainer.optimizers = optimizers
117         self.trainer.lr_schedulers = lr_schedulers
118         self.trainer.optimizer_frequencies = optimizer_frequencies
119 
120         # MODEL
121         # copy model to each gpu
122         if self.trainer.on_gpu:
123             gpu_idx = process_idx
124             self.trainer.root_gpu = gpu_idx
125             torch.cuda.set_device(self.trainer.root_gpu)
126             model.cuda(self.trainer.root_gpu)
127 
128         # set model properties before going into wrapper
129         self.trainer.copy_trainer_model_properties(model)
130 
131         # AMP
132         # run through amp wrapper before going to distributed DP
133         # TODO: remove with dropping NVIDIA AMP support
134         native_amp_available = hasattr(torch.cuda, "amp") and hasattr(torch.cuda.amp, "autocast")
135         if self.trainer.use_amp and not native_amp_available:
136             model, optimizers = model.configure_apex(amp, model, self.trainer.optimizers, self.trainer.amp_level)
137             self.trainer.optimizers = optimizers
138             self.trainer.reinit_scheduler_properties(self.trainer.optimizers, self.trainer.lr_schedulers)
139 
140         # DDP2 uses all GPUs on the machine
141         if self.trainer.distributed_backend == 'ddp' or self.trainer.distributed_backend == 'ddp_spawn':
142             device_ids = [self.trainer.root_gpu]
143         elif self.trainer.use_ddp2:
144             device_ids = self.trainer.data_parallel_device_ids
145         else:  # includes ddp_cpu
146             device_ids = None
147 
148         # allow user to configure ddp
149         model = model.configure_ddp(model, device_ids)
150 
151         # continue training routine
152         results = self.trainer.run_pretrain_routine(model)
153 
154         # get original model
155         model = self.trainer.get_model()
156 
157         # persist info in ddp_spawn
158         self.trainer.transfer_distrib_spawn_state_on_fit_end(model, mp_queue, results)
159 
160         # clean up memory
161         torch.cuda.empty_cache()
162
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py b/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py
--- a/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py
+++ b/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py
@@ -49,7 +49,8 @@
         last_path = self.mp_queue.get()
 
         # transfer back the best path to the trainer
-        self.trainer.checkpoint_callback.best_model_path = best_path
+        if self.trainer.checkpoint_callback:
+            self.trainer.checkpoint_callback.best_model_path = best_path
         # todo, pass also bets score
 
         # load last weights

{"golden_diff": "diff --git a/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py b/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py\n--- a/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py\n+++ b/pytorch_lightning/accelerator_backends/ddp_spawn_backend.py\n@@ -49,7 +49,8 @@\n         last_path = self.mp_queue.get()\n \n         # transfer back the best path to the trainer\n-        self.trainer.checkpoint_callback.best_model_path = best_path\n+        if self.trainer.checkpoint_callback:\n+            self.trainer.checkpoint_callback.best_model_path = best_path\n         # todo, pass also bets score\n \n         # load last weights\n", "issue": "Can't use None (anymore) in checkpoint_callback\n## \ud83d\udc1b Bug\r\nusing None in checkpoint_callback now errors out\r\n\r\n```\r\n-- Process 0 terminated with the following error:\r\nTraceback (most recent call last):\r\n  File \"/opt/conda/lib/python3.6/site-packages/torch/multiprocessing/spawn.py\", line 20, in _wrap\r\n    fn(i, *args)\r\n  File \"/opt/conda/lib/python3.6/site-packages/pytorch_lightning/trainer/distrib_data_parallel.py\", line 562, in ddp_train\r\n    q.put(self.checkpoint_callback.best_model_path)\r\nAttributeError: 'NoneType' object has no attribute 'best_model_path'\r\n```\r\n\r\n### To Reproduce\r\n`trainer = Trainer(checkpoint_callback=None)`\r\n\r\nRan into this issue from upgrading to masters, was using masters from a few commits ago before\r\n\r\nEdit: `False` casuses the same error as well\n", "before_files": [{"content": "# Copyright The PyTorch Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License\n\nimport os\nimport torch\nimport torch.multiprocessing as mp\nfrom pytorch_lightning.utilities.distributed import rank_zero_only\nfrom pytorch_lightning import _logger as log\n\ntry:\n    from apex import amp\nexcept ImportError:\n    APEX_AVAILABLE = False\nelse:\n    APEX_AVAILABLE = True\n\n\nclass DDPSpawnBackend(object):\n\n    def __init__(self, trainer):\n        self.trainer = trainer\n        self.mp_queue = None\n\n    def setup(self):\n        self.trainer.set_random_port()\n\n        # pass in a state q\n        smp = mp.get_context('spawn')\n        self.mp_queue = smp.SimpleQueue()\n\n    def train(self, model, nprocs):\n        mp.spawn(self.ddp_train, nprocs=nprocs, args=(self.mp_queue, model,))\n\n    def teardown(self, model):\n        # restore main state with best weights\n        best_path = self.mp_queue.get()\n        results = self.mp_queue.get()\n        last_path = self.mp_queue.get()\n\n        # transfer back the best path to the trainer\n        self.trainer.checkpoint_callback.best_model_path = best_path\n        # todo, pass also bets score\n\n        # load last weights\n        if last_path is not None and not self.trainer.testing:\n            ckpt = torch.load(last_path, map_location=lambda storage, loc: storage)\n            model.load_state_dict(ckpt)\n\n        self.trainer.model = model\n        return results\n\n    def ddp_train(self, process_idx, mp_queue, model):\n        \"\"\"\n        Entry point for ddp\n\n        Args:\n            process_idx:\n            mp_queue: multiprocessing queue\n            model:\n\n        Returns:\n\n        \"\"\"\n        # show progressbar only on progress_rank 0\n        if (self.trainer.node_rank != 0 or process_idx != 0) and self.trainer.progress_bar_callback is not None:\n            self.trainer.progress_bar_callback.disable()\n\n        # determine which process we are and world size\n        if self.trainer.use_ddp:\n            self.trainer.local_rank = process_idx\n            self.trainer.global_rank = self.trainer.node_rank * self.trainer.num_processes + process_idx\n            self.trainer.world_size = self.trainer.num_nodes * self.trainer.num_processes\n\n        elif self.trainer.use_ddp2:\n            self.trainer.local_rank = self.trainer.node_rank\n            self.trainer.global_rank = self.trainer.node_rank\n            self.trainer.world_size = self.trainer.num_nodes\n\n        # set warning rank\n        rank_zero_only.rank = self.trainer.global_rank\n\n        # set up server using proc 0's ip address\n        # try to init for 20 times at max in case ports are taken\n        # where to store ip_table\n        model.trainer = self.trainer\n        model.init_ddp_connection(\n            self.trainer.global_rank,\n            self.trainer.world_size,\n            self.trainer.is_slurm_managing_tasks\n        )\n\n        # call setup after the ddp process has connected\n        self.trainer.call_setup_hook(model)\n\n        # on world_size=0 let everyone know training is starting\n        if self.trainer.is_global_zero:\n            log.info('-' * 100)\n            log.info(f'distributed_backend={self.trainer.distributed_backend}')\n            log.info(f'All DDP processes registered. Starting ddp with {self.trainer.world_size} processes')\n            log.info('-' * 100)\n\n        # CHOOSE OPTIMIZER\n        # allow for lr schedulers as well\n        optimizers, lr_schedulers, optimizer_frequencies = self.trainer.init_optimizers(model)\n        self.trainer.optimizers = optimizers\n        self.trainer.lr_schedulers = lr_schedulers\n        self.trainer.optimizer_frequencies = optimizer_frequencies\n\n        # MODEL\n        # copy model to each gpu\n        if self.trainer.on_gpu:\n            gpu_idx = process_idx\n            self.trainer.root_gpu = gpu_idx\n            torch.cuda.set_device(self.trainer.root_gpu)\n            model.cuda(self.trainer.root_gpu)\n\n        # set model properties before going into wrapper\n        self.trainer.copy_trainer_model_properties(model)\n\n        # AMP\n        # run through amp wrapper before going to distributed DP\n        # TODO: remove with dropping NVIDIA AMP support\n        native_amp_available = hasattr(torch.cuda, \"amp\") and hasattr(torch.cuda.amp, \"autocast\")\n        if self.trainer.use_amp and not native_amp_available:\n            model, optimizers = model.configure_apex(amp, model, self.trainer.optimizers, self.trainer.amp_level)\n            self.trainer.optimizers = optimizers\n            self.trainer.reinit_scheduler_properties(self.trainer.optimizers, self.trainer.lr_schedulers)\n\n        # DDP2 uses all GPUs on the machine\n        if self.trainer.distributed_backend == 'ddp' or self.trainer.distributed_backend == 'ddp_spawn':\n            device_ids = [self.trainer.root_gpu]\n        elif self.trainer.use_ddp2:\n            device_ids = self.trainer.data_parallel_device_ids\n        else:  # includes ddp_cpu\n            device_ids = None\n\n        # allow user to configure ddp\n        model = model.configure_ddp(model, device_ids)\n\n        # continue training routine\n        results = self.trainer.run_pretrain_routine(model)\n\n        # get original model\n        model = self.trainer.get_model()\n\n        # persist info in ddp_spawn\n        self.trainer.transfer_distrib_spawn_state_on_fit_end(model, mp_queue, results)\n\n        # clean up memory\n        torch.cuda.empty_cache()\n", "path": "pytorch_lightning/accelerator_backends/ddp_spawn_backend.py"}], "after_files": [{"content": "# Copyright The PyTorch Lightning team.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License\n\nimport os\nimport torch\nimport torch.multiprocessing as mp\nfrom pytorch_lightning.utilities.distributed import rank_zero_only\nfrom pytorch_lightning import _logger as log\n\ntry:\n    from apex import amp\nexcept ImportError:\n    APEX_AVAILABLE = False\nelse:\n    APEX_AVAILABLE = True\n\n\nclass DDPSpawnBackend(object):\n\n    def __init__(self, trainer):\n        self.trainer = trainer\n        self.mp_queue = None\n\n    def setup(self):\n        self.trainer.set_random_port()\n\n        # pass in a state q\n        smp = mp.get_context('spawn')\n        self.mp_queue = smp.SimpleQueue()\n\n    def train(self, model, nprocs):\n        mp.spawn(self.ddp_train, nprocs=nprocs, args=(self.mp_queue, model,))\n\n    def teardown(self, model):\n        # restore main state with best weights\n        best_path = self.mp_queue.get()\n        results = self.mp_queue.get()\n        last_path = self.mp_queue.get()\n\n        # transfer back the best path to the trainer\n        if self.trainer.checkpoint_callback:\n            self.trainer.checkpoint_callback.best_model_path = best_path\n        # todo, pass also bets score\n\n        # load last weights\n        if last_path is not None and not self.trainer.testing:\n            ckpt = torch.load(last_path, map_location=lambda storage, loc: storage)\n            model.load_state_dict(ckpt)\n\n        self.trainer.model = model\n        return results\n\n    def ddp_train(self, process_idx, mp_queue, model):\n        \"\"\"\n        Entry point for ddp\n\n        Args:\n            process_idx:\n            mp_queue: multiprocessing queue\n            model:\n\n        Returns:\n\n        \"\"\"\n        # show progressbar only on progress_rank 0\n        if (self.trainer.node_rank != 0 or process_idx != 0) and self.trainer.progress_bar_callback is not None:\n            self.trainer.progress_bar_callback.disable()\n\n        # determine which process we are and world size\n        if self.trainer.use_ddp:\n            self.trainer.local_rank = process_idx\n            self.trainer.global_rank = self.trainer.node_rank * self.trainer.num_processes + process_idx\n            self.trainer.world_size = self.trainer.num_nodes * self.trainer.num_processes\n\n        elif self.trainer.use_ddp2:\n            self.trainer.local_rank = self.trainer.node_rank\n            self.trainer.global_rank = self.trainer.node_rank\n            self.trainer.world_size = self.trainer.num_nodes\n\n        # set warning rank\n        rank_zero_only.rank = self.trainer.global_rank\n\n        # set up server using proc 0's ip address\n        # try to init for 20 times at max in case ports are taken\n        # where to store ip_table\n        model.trainer = self.trainer\n        model.init_ddp_connection(\n            self.trainer.global_rank,\n            self.trainer.world_size,\n            self.trainer.is_slurm_managing_tasks\n        )\n\n        # call setup after the ddp process has connected\n        self.trainer.call_setup_hook(model)\n\n        # on world_size=0 let everyone know training is starting\n        if self.trainer.is_global_zero:\n            log.info('-' * 100)\n            log.info(f'distributed_backend={self.trainer.distributed_backend}')\n            log.info(f'All DDP processes registered. Starting ddp with {self.trainer.world_size} processes')\n            log.info('-' * 100)\n\n        # CHOOSE OPTIMIZER\n        # allow for lr schedulers as well\n        optimizers, lr_schedulers, optimizer_frequencies = self.trainer.init_optimizers(model)\n        self.trainer.optimizers = optimizers\n        self.trainer.lr_schedulers = lr_schedulers\n        self.trainer.optimizer_frequencies = optimizer_frequencies\n\n        # MODEL\n        # copy model to each gpu\n        if self.trainer.on_gpu:\n            gpu_idx = process_idx\n            self.trainer.root_gpu = gpu_idx\n            torch.cuda.set_device(self.trainer.root_gpu)\n            model.cuda(self.trainer.root_gpu)\n\n        # set model properties before going into wrapper\n        self.trainer.copy_trainer_model_properties(model)\n\n        # AMP\n        # run through amp wrapper before going to distributed DP\n        # TODO: remove with dropping NVIDIA AMP support\n        native_amp_available = hasattr(torch.cuda, \"amp\") and hasattr(torch.cuda.amp, \"autocast\")\n        if self.trainer.use_amp and not native_amp_available:\n            model, optimizers = model.configure_apex(amp, model, self.trainer.optimizers, self.trainer.amp_level)\n            self.trainer.optimizers = optimizers\n            self.trainer.reinit_scheduler_properties(self.trainer.optimizers, self.trainer.lr_schedulers)\n\n        # DDP2 uses all GPUs on the machine\n        if self.trainer.distributed_backend == 'ddp' or self.trainer.distributed_backend == 'ddp_spawn':\n            device_ids = [self.trainer.root_gpu]\n        elif self.trainer.use_ddp2:\n            device_ids = self.trainer.data_parallel_device_ids\n        else:  # includes ddp_cpu\n            device_ids = None\n\n        # allow user to configure ddp\n        model = model.configure_ddp(model, device_ids)\n\n        # continue training routine\n        results = self.trainer.run_pretrain_routine(model)\n\n        # get original model\n        model = self.trainer.get_model()\n\n        # persist info in ddp_spawn\n        self.trainer.transfer_distrib_spawn_state_on_fit_end(model, mp_queue, results)\n\n        # clean up memory\n        torch.cuda.empty_cache()\n", "path": "pytorch_lightning/accelerator_backends/ddp_spawn_backend.py"}]}