docs: def log_in(self, username=None, password=None,
                 code=None, redirect_uri="urn:ietf:wg:oauth:2.0:oob", refresh_token=None,
                 scopes=__DEFAULT_SCOPES, to_file=None):
          """
          Get the access token for a user.
          
          The username is the e-mail used to log in into mastodon.
  
          Can persist access token to file `to_file`, to be used in the constructor.
  
          Handles password and OAuth-based authorization.
          
          Will throw a `MastodonIllegalArgumentError` if the OAuth or the
          username / password credentials given are incorrect, and
          `MastodonAPIError` if all of the requested scopes were not granted.
  
          For OAuth2, obtain a code via having your user go to the url returned by 
          `auth_request_url()`_ and pass it as the code parameter. In this case,
          make sure to also pass the same redirect_uri parameter as you used when
          generating the auth request URL.
  
          Returns the access token as a string.
          """
          if username is not None and password is not None:
              params = self.__generate_params(locals(), ['scopes', 'to_file', 'code', 'refresh_token'])
              params['grant_type'] = 'password'
          elif code is not None:
              params = self.__generate_params(locals(), ['scopes', 'to_file', 'username', 'password', 'refresh_token'])
              params['grant_type'] = 'authorization_code'
          elif refresh_token is not None:
              params = self.__generate_params(locals(), ['scopes', 'to_file', 'username', 'password', 'code'])
              params['grant_type'] = 'refresh_token'
          else:
              raise MastodonIllegalArgumentError('Invalid arguments given. username and password or code are required.')
  
          params['client_id'] = self.client_id
          params['client_secret'] = self.client_secret
          params['scope'] = " ".join(scopes)
  
          try:
              response = self.__api_request('POST', '/oauth/token', params, do_ratelimiting=False)
              self.access_token = response['access_token']
              self.__set_refresh_token(response.get('refresh_token'))
              self.__set_token_expired(int(response.get('expires_in', 0)))
          except Exception as e:
              if username is not None or password is not None:
                  raise MastodonIllegalArgumentError('Invalid user name, password, or redirect_uris: %s' % e)
              elif code is not None:
                  raise MastodonIllegalArgumentError('Invalid access token or redirect_uris: %s' % e)
              else:
                  raise MastodonIllegalArgumentError('Invalid request: %s' % e)
  
          received_scopes = response["scope"].split(" ")
          for scope_set in self.__SCOPE_SETS.keys():
              if scope_set in received_scopes:
                  received_scopes += self.__SCOPE_SETS[scope_set]
          
          if not set(scopes) <= set(received_scopes):
              raise MastodonAPIError(
                  'Granted scopes "' + " ".join(received_scopes) + '" do not contain all of the requested scopes "' + " ".join(scopes) + '".')
  
          if to_file is not None:
              with open(to_file, 'w') as token_file:
                  token_file.write(response['access_token'] + '\n')
          
          self.__logged_in_id = None
          
          return response['access_token']