docstr: :returns: if accepted, return None, otherwise return a reason for rejection
docstr_tok: [":","returns",":","if","accepted",",","return","None",",","otherwise","return","a","reason","for","rejection"]
code: def _check_reasons_to_reject(
      self, request: averaging_pb2.JoinRequest, context: P2PContext
  ) -> Optional[averaging_pb2.MessageFromLeader]:
      """:returns: if accepted, return None, otherwise return a reason for rejection"""
      if not self.is_looking_for_group or self.assembled_group.done():
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.NOT_LOOKING_FOR_GROUP
          )
  
      if (
          request.ListFields() == 3
          and not isinstance(request.schema_hash, bytes)
          or len(request.schema_hash) == 0
          or not isinstance(request.expiration, DHTExpiration)
          or not isfinite(request.expiration)
          or self.client_mode
          or not isinstance(request.group_key, GroupKey)
      ):
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.PROTOCOL_VIOLATION
          )
  
      elif request.schema_hash != self.schema_hash:
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.BAD_SCHEMA_HASH
          )
      elif request.group_key != self.group_key_manager.current_key:
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.BAD_GROUP_KEY
          )
      elif self.potential_leaders.declared_group_key is None:
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.NOT_DECLARED
          )
      elif self.potential_leaders.declared_expiration_time > (
          request.expiration or float("inf")
      ):
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.BAD_EXPIRATION_TIME
          )
      elif self.current_leader is not None:
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.NOT_A_LEADER,
              suggested_leader=self.current_leader.to_bytes(),
          )
      elif (
          context.remote_id == self.peer_id
          or context.remote_id in self.current_followers
      ):
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.DUPLICATE_PEER_ID
          )
      elif (
          self.target_group_size is not None
          and len(self.current_followers) + 1 >= self.target_group_size
      ):
          return averaging_pb2.MessageFromLeader(
              code=averaging_pb2.GROUP_IS_FULL
          )
      else:
          return None
  
imports: from __future__ import annotations
  import asyncio
  import concurrent.futures
  import contextlib
  import random
  from math import isfinite
  from typing import AsyncIterator, Dict, Optional, Set, Tuple, Type
  from hivemind.averaging.control import StepControl
  from hivemind.averaging.group_info import GroupInfo
  from hivemind.averaging.key_manager import GroupKey, GroupKeyManager
  from hivemind.dht import DHT, DHTID
  from hivemind.p2p import P2P, P2PContext, P2PDaemonError, P2PHandlerError, PeerID, ServicerBase
  from hivemind.proto import averaging_pb2
  from hivemind.utils import DHTExpiration, TimedStorage, get_dht_time, get_logger, timed_storage
  from hivemind.utils.asyncio import anext, cancel_and_wait
label_desc: Use image node_id 5 for calling the Matchmaking obj's underlying member method code with example usage: obj._check_reasons_to_reject(request, context) and returns: averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, averaging_pb2, None