Skip to content
Advertisement

requests.auth.AuthBase TypeError on call

From the docs at https://docs.python-requests.org/en/master/user/authentication/

I gathered that the __call__ function in my own Auth Class should have the r argument,

However when i go to call this class in requests.get(auth=MyClass), I get the error TypeError: __call__() missing 1 required positional argument: 'r'

The code for my class can be found here https://pastebin.com/YDZ2DeaT

import requests
import time
import base64

from requests.auth import AuthBase

class TokenAuth(AuthBase):
    """Refreshes SkyKick token, for use with all Skykick requests"""
    def __init__(self, Username: str, SubKey: str):
        self.Username = Username
        self.SubKey = SubKey
    
    # Initialise with no token and instant expiry
        self.Token = None
        self.TokenExpiry = time.time()
    

        self.Headers = {
            # Request headers

            'Content-Type'             : 'application/x-www-form-urlencoded',
            'Ocp-Apim-Subscription-Key': self.SubKey,

        }

        self.Body = {
        # Request body
            'grant_type': 'client_credentials',
            'scope'     : 'Partner'
        }

    def regenToken(self):
    # Sends request to regenerate token
        try:
        # Get key from API
            response = requests.post("https://apis.skykick.com/auth/token",
                                     headers=self.Headers,
                                     auth=(self.Username, self.SubKey),
                                     data=self.Body,
                                     ).json()
        except: 
            raise Exception("Sending request failed, check connection.")

        # API errors are inconsistent, easiest way to catch them
        if "error" in response or "statusCode" in response:
            raise Exception(
                "Token requesting failed, cannot proceed with any Skykick actions, exiting.n"
                f"Error raised was {response}")

    # Get token from response and set expiry
        self.Token = response["access_token"]
        self.TokenExpiry = time.time() + 82800

    def __call__(self, r):
    
    # If token expiry is now or in past, call regenToken
        if self.TokenExpiry <= time.time():
            self.regenToken()
    # Set headers and return complete requests.Request object
        r.headers["Authorization"] = f"Bearer {self.Token}"
        return r

# Initialise our token class, so it is ready to call
TokenClass = TokenAuth("test", "1234")

#Send request with class as auth method.
requests.get("https://apis.skykick.com/whoami", auth=TokenClass())

I’ve tried using the example code, which works, but I can’t figure out why mine won’t work.

python-requests version is 2.25.1

Advertisement

Answer

I think I know what is going on.

This line instantiates an object, called TokenClass

TokenClass = TokenAuth("test", "1234")

then here,

requests.get("https://apis.skykick.com/whoami", auth=TokenClass())

you are calling that object like a function

when you call an object like a function, python looks for the __call__ method of the object.

And you are not calling in any arguments here. What you have is roughly the same as this I think

requests.get("https://apis.skykick.com/whoami", auth=TokenClass.__call__())

and so it complains that you are missing the r argument


This is their example:

import requests
class MyAuth(requests.auth.AuthBase):
    def __call__(self, r):
        # Implement my authentication
        return r

url = 'https://httpbin.org/get'
requests.get(url, auth=MyAuth())

MyAuth is a class that they define, and then MyAuth() creates an instance of it that they pass in to get.

Yours is more like this

import requests
class MyAuth(requests.auth.AuthBase):
    def __call__(self, r):
        # Implement my authentication
        return r

url = 'https://httpbin.org/get'

myAuth = MyAuth() # create an instance of the class

requests.get(url, auth=myAuth()) # call the instance and pass in result

It could also be written like this

import requests
class MyAuth(requests.auth.AuthBase):
    def __call__(self, r):
        # Implement my authentication
        return r

url = 'https://httpbin.org/get'


requests.get(url, auth=MyAuth()())

This program with produce the same error you are getting

import requests
class MyAuth(requests.auth.AuthBase):
    def __call__(self, r):
        # Implement my authentication
        return r

url = 'https://httpbin.org/get'

MyAuth()()

because when you put () after a class, you get an instance, and when you put () after an instance, you call the __call__ method

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement