docstr: Finds a (lhs, rhs) partition pair that has not already been acquired
  this epoch, and where neither the lhs nor rhs partitions are currently
  locked. Locks this lhs and rhs until `release_pair` is called. Will try
  to find a pair that has the same lhs (if not, rhs) as old_bucket.
  
  If no pair is available, returns None.
  
  Returns:
      pair: a (lhs, rhs) partition pair. lhs and rhs are locked until
            `release_pair` is called.
            If no pair is available, None is returned.
      remaining: The number of pairs remaining. When this is 0 then the
                 epoch is done.
docstr_tok: ["Finds","a","(","lhs",",","rhs",")","partition","pair","that","has","not","already","been","acquired","this","epoch",",","and","where","neither","the","lhs","nor","rhs","partitions","are","currently","locked",".","Locks","this","lhs","and","rhs","until","`","release_pair","`","is","called",".","Will","try","to","find","a","pair","that","has","the","same","lhs","(","if","not",",","rhs",")","as","old_bucket",".","If","no","pair","is","available",",","returns","None",".","Returns",":","pair",":","a","(","lhs",",","rhs",")","partition","pair",".","lhs","and","rhs","are","locked","until","`","release_pair","`","is","called",".","If","no","pair","is","available",",","None","is","returned",".","remaining",":","The","number","of","pairs","remaining",".","When","this","is","0","then","the","epoch","is","done","."]
code: def acquire_bucket(
      self, rank: Rank, maybe_old_bucket: Optional[Bucket] = None
  ) -> Tuple[Optional[Bucket], int]:
      """
      Finds a (lhs, rhs) partition pair that has not already been acquired
      this epoch, and where neither the lhs nor rhs partitions are currently
      locked. Locks this lhs and rhs until `release_pair` is called. Will try
      to find a pair that has the same lhs (if not, rhs) as old_bucket.
  
      If no pair is available, returns None.
  
      Returns:
          pair: a (lhs, rhs) partition pair. lhs and rhs are locked until
                `release_pair` is called.
                If no pair is available, None is returned.
          remaining: The number of pairs remaining. When this is 0 then the
                     epoch is done.
      """
      remaining = self.nparts_lhs * self.nparts_rhs - len(self.done)
  
      locked_entities_parts: Dict[
          Tuple[EntityName, Partition], Rank
      ] = {}
      for bucket, other_rank in self.active.items():
          locked_entities_parts.update(
              ((entity, bucket.lhs), other_rank)
              for entity in self.entities_lhs
          )
          locked_entities_parts.update(
              ((entity, bucket.rhs), other_rank)
              for entity in self.entities_rhs
          )
  
      acquirable_lhs_parts: List[Partition] = []
      for part in range(self.nparts_lhs):
          if self._can_acquire(
              rank, part, locked_entities_parts, Side.LHS
          ):
              acquirable_lhs_parts.append(part)
  
      acquirable_rhs_parts: List[Partition] = []
      for part in range(self.nparts_rhs):
          if self._can_acquire(
              rank, part, locked_entities_parts, Side.RHS
          ):
              acquirable_rhs_parts.append(part)
  
      acquirable_buckets: List[Bucket] = []
      for part_lhs in acquirable_lhs_parts:
          for part_rhs in acquirable_rhs_parts:
              bucket = Bucket(part_lhs, part_rhs)
              if bucket not in self.done and self._is_initialized(
                  bucket
              ):
                  acquirable_buckets.append(bucket)
  
      if len(acquirable_buckets) == 0:
          return None, remaining
  
      new_bucket = self._pick_bucket(
          acquirable_buckets, maybe_old_bucket
      )
  
      self.active[new_bucket] = rank
      self.done.add(new_bucket)
      if self.initialized_entities_partitions is not None:
          self.initialized_entities_partitions.update(
              (entity, new_bucket.lhs) for entity in self.entities_lhs
          )
          self.initialized_entities_partitions.update(
              (entity, new_bucket.rhs) for entity in self.entities_rhs
          )
      logger.info(
          f"Bucket {new_bucket} acquired by trainer {rank}: active= {self.active}"
      )
      return new_bucket, remaining - 1
  
imports: import logging
  import random
  from abc import ABC, abstractmethod
  from collections import defaultdict
  from statistics import mean
  from typing import Dict, List, NamedTuple, Optional, Set, Tuple
  from torchbiggraph.config import BucketOrder
  from torchbiggraph.distributed import Startable
  from torchbiggraph.rpc import Client, Server
  from torchbiggraph.stats import Stats, StatsHandler
  from torchbiggraph.types import Bucket, EntityName, Partition, Rank, Side
label_desc: Use image node_id 6 for calling the LockServer obj's underlying member method code with example usage: obj.acquire_bucket(rank, maybe_old_bucket) and returns: new_bucket,  unknown, None,  remaining