code: async def aiter(*args):
      
      if not args:
  
          raise TypeError('aiter() expected at least 1 arguments, got 0')
  
      if len(args) > 2:
  
          raise TypeError(
              'aiter() expected at most 2 arguments, got {}'.format(len(args))
          )
  
      if len(args) == 2:
  
          func, sentinel = args
          if not isinstance(func, types.CoroutineType):
  
              raise TypeError('aiter(v, w): v must be async callable')
          # TODO: repeating call thing
          raise NotImplementedError()
  
      obj = args[0]
      if hasattr(obj, '__anext__'):
  
          return obj
  
      if hasattr(obj, '__aiter__'):
  
          return (await obj.__aiter__())
  
      if hasattr(obj, '__iter__') or hasattr(obj, '__next__'):
  
          return AsyncIterWrapper(iter(obj))
  
      raise TypeError("'{}' object is not iterable".format(type(args[0])))
docs: Return an iterator object.
  
      Args:
          obj: An object that implements the __iter__ or __aiter__ method.
          sentinel: An optional sentinel value to look for while iterator.
  
      Return:
          iterable: Some iterable that provides a __anext__ method.
  
      Raises:
          TypeError: If only the object is given and it is not iterable.
          TypeError: If two arguments are given and the first is not an async
              callable.
  
      This function behaves very differently based on the number of arguments
      given. If only the first argument is present the method will return
      an async iterable that implements the __anext__ method by called the
      given object's __aiter__. If the object does not define __aiter__ but does
      define __iter__ then the result will be an AsyncIterWrapper that contains
      the original iterable. This form of the function can be used to coerce all
      iterables, async or not, into async iterables for interoperablilty.
  
      If the second argument is given then the first argument _must_ be an async
      callable. The returned value will still be an iterable implementing the
      __aiter__ method, but each call to that method will call the underlying
      async callable. If the value returned from the async callable matches the
      sentinel value then StopAsyncIteration is raised. Otherwise the value is
      returned.