BaseHTTPRequestHandler with custom instance
Asked Answered
H

6

19

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!

Huskey answered 26/8, 2013 at 12:42 Comment(0)
D
16

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

Decile answered 26/8, 2013 at 13:20 Comment(3)
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.Spew
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. XDPleuron
@Philippe T. Just saved another life! BTW take out that #Doesnt work comment out of the code.Superabundant
E
24

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()
Estelleesten answered 3/11, 2014 at 22:15 Comment(3)
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 youCara
@Cara 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 :-)Estelleesten
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 clarityFlanigan
D
16

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

Decile answered 26/8, 2013 at 13:20 Comment(3)
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.Spew
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. XDPleuron
@Philippe T. Just saved another life! BTW take out that #Doesnt work comment out of the code.Superabundant
A
11

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()
Autocade answered 17/5, 2015 at 15:34 Comment(2)
Good answer, but I believe it should be "server.t1 = t1" instead of "self.t1 = t1" in the http_server constructor.Rolandrolanda
as well as server.t1 = t1 needs to go after the HTTPServer() assignmentThanatopsis
F
3

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()
Flanigan answered 19/5, 2021 at 21:10 Comment(0)
F
1

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()
Flanigan answered 19/5, 2021 at 21:15 Comment(0)
B
0

Encountered the same issue and was trying to follow @XaF's answer; cannot comment due to low cool point value, so adding an answer below.

In my case I have the HTTPServer as a 'private' member of the server class, and did not realize that Python would handle 'private' member such that the corresponding member accessed in the server instance of the handler is actually prepended with name of the server class, which in OP's example would be self.server._http_server__t1. So use self.server._<server class name>__<private member name> instead of self.server.<member name>.

Bookbinder answered 19/10, 2021 at 5:23 Comment(1)
Is there a way to configure python not to show python versionSnipes

© 2022 - 2024 — McMap. All rights reserved.