17

this is my http server:

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

class test:
    def show(self):
        return "aaaa"

class http_server:
    def __init__(self, t1):
        self.t1 = t1
        server = HTTPServer(('', 8080), myHandler)
        server.serve_forever()

class myHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.t1.show()) #Doesnt work
        return

class main:
    def __init__(self):
        self.t1 = test()
        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()

I need to acces instance t1 inside of myHander.

Is there any way how to do it ?

Thanks!

Peter
  • 539
  • 1
  • 7
  • 15

5 Answers5

20

Slightly better version, where t1 will not be the same for each instance.

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

class test:
    def show(self):
        return "aaaa"

class http_server:
    def __init__(self, t1):
        def handler(*args):
            myHandler(t1, *args)
        server = HTTPServer(('', 8080), handler)
        server.serve_forever()

class myHandler(BaseHTTPRequestHandler):
    def __init__(self, t1, *args):
        self.t1 = t1
        BaseHTTPRequestHandler.__init__(self, *args)

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.t1.show()) #Doesnt work
        return

class main:
    def __init__(self):
        self.t1 = test()

        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()
rsmoorthy
  • 2,152
  • 22
  • 25
  • 1
    Hi, i don't understand how handler can work, can you explain me? That function just create a instance of myHandler but then it don't return anything. Thank you – Francesco Feb 07 '16 at 18:14
  • 4
    @Francesco For a better readability, a return statement would have made sense. However, as it turns out, HTTPServer class just calls the handler function and does not bother about its return value. So not returning any thing still works out. If you look at "class BaseServer" (base class for HTTPServer) - the finish_request method just calls the passed RequestHandlerClass (while passing a ref to itself), and does not bother about responses from this class. So the above code works :-) – rsmoorthy Feb 08 '16 at 19:22
  • To be more precise because this caught me for a minute, HTTPServer **instantiates** the handler rather than **calls** it (effectively by calling `Handler(args_to_init)`). Because @rsmoorthy's `handler` function quacks like a regular instantiation of Handler the HTTPServer can "instantiate" with it, even though really it just calls the `handler` function. I added another answer below doing this same thing but using `functools.partial` to hopefully add clarity – Andrew May 19 '21 at 21:07
12

there a way to do it is to set the property to the class :

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

class test:
    def show(self):
        return "aaaa"

class http_server:
    def __init__(self, t1):
        myHandler.t1 = t1
        server = HTTPServer(('', 8080), myHandler)
        server.serve_forever()

class myHandler(BaseHTTPRequestHandler):
    t1 = None
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.t1.show()) #Doesnt work
        return

class main:
    def __init__(self):
        self.t1 = test()

        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()

You have to be careful that's every where you use myHandler that's will be the same instance of t1

Philippe T.
  • 1,114
  • 7
  • 11
  • Now THIS saved my life! Much simpler (at least for now) to instantiate the class without override the __init__ method, and then set `handler.t1 = value`. – George Jul 12 '16 at 15:53
  • I would have never thought to use a static class member. Instead I wasted more than an hour searching how to access the instance the `HTTPServer` creates internally (based on the class you have passed onto it as a handler). Needless to say it exploded into a typical chicken-and-egg problem - handler's constructor needs server's instance, which is obviously not present at the time the handler is created outside the server's class. XD – rbaleksandar Feb 15 '18 at 14:08
  • @Philippe T. Just saved another life! BTW take out that #Doesnt work comment out of the code. – Dami May 25 '20 at 08:59
10

I know I'm answering pretty late, but that could probably be helpful for future viewers. There is a really easy way to access t1 like it was asked by using the server variable of the BaseHTTPRequestHandler object:

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

class test:
    def show(self):
        return "aaaa"

class http_server:
    def __init__(self, t1):
        server = HTTPServer(('', 8080), myHandler)
        server.t1 = t1
        server.serve_forever()

class myHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.server.t1.show())
        return

class main:
    def __init__(self):
        self.t1 = test()
        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()
XaF
  • 203
  • 3
  • 5
0

Another flavor of answer to this 8-year-old question :) I too wanted to avoid using class variables that share across all Handler objects just in case, but it took me a minute to understand why @rsmoorthy's answer worked. This is basically the same answer as his, but using functools.partial to add clarity.

As HTTPServer expects the handler as a RequestHandlerClass, we can't fully instantiate the class. But we can give our subclass a custom __init__ that accepts additional data, then use functools.partial to fill that extra info in for HTTPServer. This way it just instantiates our handler like it wants to, but we still get t1 passed inside.

from http.server import BaseHTTPRequestHandler, HTTPServer
import functools


class test:
    def show(self):
        return b"aaaa"

class http_server:
    def __init__(self, t1):
        handler_partial = functools.partial(Handler, t1=t1)
        server = HTTPServer(('', 8080), handler_partial)
        server.serve_forever()

class Handler(BaseHTTPRequestHandler):
    def __init__(self, *args, t1=None, **kwargs):
        # Assign before super().__init__ because init is what triggers parsing the request
        self.t1 = t1
        super().__init__(*args, **kwargs)

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type','text/html')
        self.end_headers()
        self.wfile.write(self.t1.show())
        return

class main:
    def __init__(self):
        self.t1 = test()
        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()
Andrew
  • 299
  • 3
  • 10
0

Aaaand another answer to this old question, this time using a factory function that creates subclasses of BaseHTTPRequestHandler with our t1 already available.

from http.server import BaseHTTPRequestHandler, HTTPServer

class test:
    def show(self):
        return b"aaaa"

class http_server:
    def __init__(self, t1):
        myHandler = handlerFactory(t1)
        server = HTTPServer(('', 8080), myHandler)
        server.serve_forever()

def handlerFactory(t1):
    class myHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/html')
            self.end_headers()
            self.wfile.write(t1.show())
            return
    return myHandler

class main:
    def __init__(self):
        self.t1 = test()
        self.server = http_server(self.t1)

if __name__ == '__main__':
    m = main()
Andrew
  • 299
  • 3
  • 10