code: def _apportion_ports(
      worker_port: str | None,
      nanny_port: str | None,
      n_workers: int,
      nanny: bool,
  ) -> list[dict[str, Any]]:
      """Spread out evenly --worker-port and/or --nanny-port ranges to the workers and
      nannies, avoiding overlap.
  
      Returns
      =======
      List of kwargs to pass to the Worker or Nanny constructors
      """
      seen = set()
  
      def parse_unique(s: str | None) -> Iterator[int | None]:
          ports = parse_ports(s)
          if ports in ([0], [None]):
              for _ in range(n_workers):
                  yield ports[0]
          else:
              for port in ports:
                  if port not in seen:
                      seen.add(port)
                      yield port
  
      worker_ports_iter = parse_unique(worker_port)
      nanny_ports_iter = parse_unique(nanny_port)
  
      # [(worker ports, nanny ports), ...]
      ports: list[tuple[set[int | None], set[int | None]]] = [
          (set(), set()) for _ in range(n_workers)
      ]
  
      ports_iter = iter(ports)
      more_wps = True
      more_nps = True
      while more_wps or more_nps:
          try:
              worker_ports_i, nanny_ports_i = next(ports_iter)
          except StopIteration:
              # Start again in round-robin
              ports_iter = iter(ports)
              continue
  
          try:
              worker_ports_i.add(next(worker_ports_iter))
          except StopIteration:
              more_wps = False
          try:
              nanny_ports_i.add(next(nanny_ports_iter))
          except StopIteration:
              more_nps = False
  
      kwargs = []
      for worker_ports_i, nanny_ports_i in ports:
          if not worker_ports_i or not nanny_ports_i:
              if nanny:
                  raise ValueError(
                      f"Not enough ports in range --worker_port {worker_port} "
                      f"--nanny_port {nanny_port} for {n_workers} workers"
                  )
              else:
                  raise ValueError(
                      f"Not enough ports in range --worker_port {worker_port} "
                      f"for {n_workers} workers"
                  )
  
          # None and int can't be sorted together,
          # but None and 0 are guaranteed to be alone
          wp: Any = sorted(worker_ports_i)
          if len(wp) == 1:
              wp = wp[0]
          if nanny:
              np: Any = sorted(nanny_ports_i)
              if len(np) == 1:
                  np = np[0]
              kwargs_i = {"port": np, "worker_port": wp}
          else:
              kwargs_i = {"port": wp}
  
          kwargs.append(kwargs_i)
  
      return kwargs
  
imports: from __future__ import annotations
  import asyncio
  import atexit
  import gc
  import logging
  import os
  import sys
  import warnings
  from collections.abc import Iterator
  from contextlib import suppress
  from typing import Any
  import click
  from tlz import valmap
  from tornado.ioloop import TimeoutError
  import dask
  from dask.system import CPU_COUNT
  from distributed import Nanny
  from distributed._signals import wait_for_signals
  from distributed.comm import get_address_host_port
  from distributed.compatibility import asyncio_run
  from distributed.config import get_loop_factory
  from distributed.deploy.utils import nprocesses_nthreads
  from distributed.preloading import validate_preload_argv
  from distributed.proctitle import enable_proctitle_on_children, enable_proctitle_on_current
  from distributed.utils import import_term, parse_ports
label_desc: Use image node_id 2 for calling a global function with example usage: _apportion_ports(worker_port, nanny_port, n_workers, nanny) and returns: kwargs