class_docstr: Concrete implementation of the `MasterLauncher` interface. See its documentation to get a list of the inherited methods and attributes.
  
  This class implements the logic for starting a the DASK master instance (i.e. scheduler in DASK terms) on localhost.
class_docstr_tok: ["Concrete","implementation","of","the","`","MasterLauncher","`","interface",".","See","its","documentation","to","get","a","list","of","the","inherited","methods","and","attributes",".","This","class","implements","the","logic","for","starting","a","the","DASK","master","instance","(","i.e",".","scheduler","in","DASK","terms",")","on","localhost","."]
docstr: Launch a master instance.
  
  Note:
      If you create a custom subclass of MasterLauncher which will not start the master instance on localhost
      then you should pass the debug flag on to `execute_task()` of the `RuntimeGroup` or `Runtime` so that you
      can benefit from the debug feature of `RuntimeTask.execute()`.
  
  Args:
      ports: Port where the master should be started. If a list is given then the first port that is free in the
             `RuntimeGroup` will be used. The actual chosen port can be requested via the property `port`.
      timeout: Timeout (s) after which an MasterStartError is raised if master instance not started yet.
      debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. If, `False` then
             the stdout/stderr will be added to python logger with level debug after each `RuntimeTask` step. Defaults to
             `False`.
  
  Returns:
      List[int]: In case a port list was given the updated port list will be returned. Otherwise an empty list.
  
  Raises:
      PortInUseError: If a single port is given and it is not free in the `RuntimeGroup`.
      NoPortsLeftError: If a port list was given and none of the ports is actually free in the `RuntimeGroup`.
      MasterStartError: If master was not started after the specified `timeout`.
docstr_tok: ["Launch","a","master","instance",".","Note",":","If","you","create","a","custom","subclass","of","MasterLauncher","which","will","not","start","the","master","instance","on","localhost","then","you","should","pass","the","debug","flag","on","to","`","execute_task","(",")","`","of","the","`","RuntimeGroup","`","or","`","Runtime","`","so","that","you","can","benefit","from","the","debug","feature","of","`","RuntimeTask.execute","(",")","`",".","Args",":","ports",":","Port","where","the","master","should","be","started",".","If","a","list","is","given","then","the","first","port","that","is","free","in","the","`","RuntimeGroup","`","will","be","used",".","The","actual","chosen","port","can","be","requested","via","the","property","`","port","`",".","timeout",":","Timeout","(","s",")","after","which","an","MasterStartError","is","raised","if","master","instance","not","started","yet",".","debug",":","If","`","True","`",",","stdout\/stderr","from","the","runtime","will","be","printed","to","stdout","of","localhost",".","If",",","`","False","`","then","the","stdout\/stderr","will","be","added","to","python","logger","with","level","debug","after","each","`","RuntimeTask","`","step",".","Defaults","to","`","False","`",".","Returns",":","List","[","int","]",":","In","case","a","port","list","was","given","the","updated","port","list","will","be","returned",".","Otherwise","an","empty","list",".","Raises",":","PortInUseError",":","If","a","single","port","is","given","and","it","is","not","free","in","the","`","RuntimeGroup","`",".","NoPortsLeftError",":","If","a","port","list","was","given","and","none","of","the","ports","is","actually","free","in","the","`","RuntimeGroup","`",".","MasterStartError",":","If","master","was","not","started","after","the","specified","`","timeout","`","."]
code: def start(
      self,
      ports: Union[List[int], int],
      timeout: int = 3,
      debug: bool = False,
  ) -> List[int]:
      """Launch a master instance.
  
      Note:
          If you create a custom subclass of MasterLauncher which will not start the master instance on localhost
          then you should pass the debug flag on to `execute_task()` of the `RuntimeGroup` or `Runtime` so that you
          can benefit from the debug feature of `RuntimeTask.execute()`.
  
      Args:
          ports: Port where the master should be started. If a list is given then the first port that is free in the
                 `RuntimeGroup` will be used. The actual chosen port can be requested via the property `port`.
          timeout: Timeout (s) after which an MasterStartError is raised if master instance not started yet.
          debug: If `True`, stdout/stderr from the runtime will be printed to stdout of localhost. If, `False` then
                 the stdout/stderr will be added to python logger with level debug after each `RuntimeTask` step. Defaults to
                 `False`.
  
      Returns:
          List[int]: In case a port list was given the updated port list will be returned. Otherwise an empty list.
  
      Raises:
          PortInUseError: If a single port is given and it is not free in the `RuntimeGroup`.
          NoPortsLeftError: If a port list was given and none of the ports is actually free in the `RuntimeGroup`.
          MasterStartError: If master was not started after the specified `timeout`.
      """
  
      _ports: Union[List[int], int] = (
          ports.copy() if isinstance(ports, list) else ports
      )
  
      if debug:
          self.log.debug(
              "The debug flag has no effect in LocalMasterLauncher."
          )
  
      if not isinstance(_ports, list):
          if _utils.localhost_has_free_port(
              _ports
          ) and self._group.has_free_port(
              _ports, exclude_hosts=Runtime.LOCALHOST
          ):
              master_port = _ports
          else:
              raise PortInUseError(_ports, self._group)
  
      else:
          master_port = self._group.get_free_port(
              _ports
          )  # Raises NoPortsLeftError
          _ports = _utils.get_remaining_ports(_ports, master_port)
  
      self._process = Popen(
          ["dask-scheduler", "--port", str(master_port)]
      )
  
      time.sleep(timeout)  # Needed for being able to check the port
  
      if not _utils.localhost_has_free_port(master_port):
          self._port = master_port
          self.log.info(
              "Dask scheduler started on localhost on port "
              + str(self._port)
          )
      else:
          self.log.debug(
              "Dask scheduler could NOT be started successfully on port "
              + str(self._port)
          )
          cause = f"The master port {master_port} is still free when checking after the timeout of {timeout} seconds."
          raise MasterStartError("localhost", master_port, cause)
  
      # Sets up ssh tunnel for scheduler such that all communication is routed over the
      # local machine and all entities can talk to each the scheduler on localhost.
      self.log.debug(
          "Expose the Dask scheduler port in the RuntimeGroup."
      )
      self._group.expose_port_to_runtimes(self._port)
  
      # Return an empty list if a single port was provided
      return _ports if isinstance(_ports, list) else []
  
imports: import time
  from subprocess import Popen
  from typing import List, Optional, Union
  from distributed import Client
  from lazycluster import Runtime, RuntimeGroup, RuntimeTask, _utils
  from lazycluster.cluster import MasterLauncher, MasterWorkerCluster, WorkerLauncher
  from lazycluster.cluster.exceptions import MasterStartError
  from lazycluster.exceptions import NoPortsLeftError, PortInUseError
label_desc: Use image node_id 1 for calling the LocalMasterLauncher obj's underlying member method code with example usage: obj.start(ports, timeout, debug) and returns: unknown