1

I want to streamline/reduce my code, so I try to put initializations of classes with repeated parameters in their own, extended classes. This is a REST API based on Pyramid & Cornice.

How would I initialize a pyramid.httpexceptions.HTTPUnauthorized when I'm always adding the same headers on initialization? This also applies to other HTTP responses where I initialize them repeatedly without changing their parameters.

Currently I've come up with this to extend the class:

class _401(HTTPUnauthorized):
    def basic_jwt_header(self):
        self.headers.add('WWW-Authenticate','JWT')
        self.headers.add('WWW-Authenticate', 'Basic realm="Please log in"')
        return self

    def jwt_header(self):
        self.headers.add('WWW-Authenticate','JWT')
        return self

which I use in a view like this:

@forbidden_view_config()
def authenticate(request):
    response = _401()
    return _401.basic_jwt_header(response)

But it does not feel and look right. Is there a better, cleaner way?

Christian Benke
  • 517
  • 7
  • 26

2 Answers2

2

Create an __init__ method on the class:

class _401(HTTPUnauthorized):

    def __init__(self):
        # call base class __init__ first, which will set up the
        # headers instance variable
        super(_401, self).__init__()
        # in Python 3, just use this:
        # super().__init__()

        # now add the headers that you always enter
        self.headers.add('WWW-Authenticate','JWT')
        self.headers.add('WWW-Authenticate', 'Basic realm="Please log in"')

resp = _401()
print resp.headers
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
  • Ah, `super()` is the magic glue! Even nicer in Python3: http://stackoverflow.com/a/576183/570722 - maybe you could add that info? – Christian Benke Jan 24 '16 at 18:06
1

Since you are using two different methods after instantiating your _401 instance, then you might be better off using class-level factory methods, which will do both the instance creation and setting the desired headers:

class _401(HTTPUnauthorized):

    @classmethod
    def basic_jwt_header(cls):
        ret = cls()
        ret.headers.add('WWW-Authenticate','JWT')
        ret.headers.add('WWW-Authenticate', 'Basic realm="Please log in"')
        return ret

    @classmethod
    def jwt_header(cls):
        ret = cls()
        ret.headers.add('WWW-Authenticate','JWT')
        return ret

resp = _401.basic_jwt_header()
print resp.headers

Now there's no need for creating __init__, or calling super() or whatever. We use cls instead of the explicit _401 class in support of any future subclassing of _401.

PaulMcG
  • 62,419
  • 16
  • 94
  • 130