python- split() doesn't work inside __init__ -
i writing code serve html file using wsgi.when write straight forward function no error :
from wsgiref.simple_server import make_server import os ... ... def app(environ, start_response): path_info = environ["path_info"] resource = path_info.split("/")[1] #i no error here split works totally fine.
now when try put code inside class error nonetype has no attribute split. perhaps environ
inside __init__
doesn't initialised , that's why split returns nothing. following file in class candy
resides :
import os class candy: def __init__(self): #self.environ = environ #self.start = start_response self.status = "200 ok" self.headers = [] def __call__(self , environ , start_response): self.environ = environ self.start = start_response #headers = [] def content_type(path): if path.endswith(".css"): return "text/css" else: return "text/html" def app(self): path_info = self.environ["path_info"] resource = path_info.split("/")[1] #headers = [] self.headers.append(("content-type", content_type(resource))) if not resource: resource = "login.html" resp_file = os.path.join("static", resource) try: open(resp_file, "r") f: resp_file = f.read() except exception: self.start("404 not found", self.headers) return ["404 not found"] self.start("200 0k", self.headers) return [resp_file]
following server.py
file invoke make_server :
from wsgiref.simple_server import make_server candy import candy #from app import candy_request candy_class = candy() httpd = make_server('localhost', 8000, candy_class.app) print "serving http on port 8000..." # respond requests until process killed httpd.serve_forever() # alternative: serve 1 request, exit #httpd.handle_request()
any ? how error sorted , right in assumption?
to explain you're doing wrong here, let's start simple concepts - wsgi application is.
wsgi application callable receives request environment, , callback function starts response (sends status line , headers user). then, callable must return 1 or more strings, constitute response body.
in simplest form, have working it's just
def app(environ, start_response): start_response("200 ok", [("content-type", "text/plain")]) return "hello, world" make_server('localhost', 8000, app).serve_forever()
whenever request comes, app
function gets called, starts response , returns string (or return iterable of multiple strings, e.g. ["hello, ", "world"]
)
now, if want class, works this:
class myapp(object): def __init__(self): pass def __call__(self, environ, start_response): start_response("200 ok", [("content-type", "text/plain")]) return "something" app = myapp() make_server("localhost", 8000, app).serve_forever()
in case, callable app
, , it's __call__
method of caddy
class instance.
when request comes, app.__call__
gets called (__call__
magic method turns class instance in callable), , otherwise works same app
function first example. except have class instance (with self
), can pre-configuration in __init__
method. without doing in __init__
it's useless. e.g., more realistic example this:
class myapp(object): def __init__(self): self.favorite_color = "blue" def __call__(self, environ, start_response): start_response("200 ok", [("content-type", "text/plain")]) return "my favorite color {}".format(self.favorite_color) ...
then, there's thing. want streaming response, generated on time. maybe it's big, or maybe takes while. that's why wsgi applications can return iterable, rather string.
def app(environ, start_response): start_response("200 ok", [("content-type", "text/plain")])) yield "this triumph\n" time.sleep(1) yield "i'm making note here\n" time.sleep(1) yield "huge success\n" make_server("localhost", 8000, app).serve_forever()
this function returns generator returns text, piece piece. although browser may not show this, try running curl http://localhost:8000/
.
now, same classes be:
class myapp(object): def __init__(self, environ, start_response): self.environ = environ self.start = start_response def __iter__(self): self.start("200 ok", [("content-type", "text/plain")])) yield "this triumph\n" time.sleep(1) yield "i'm making note here\n" time.sleep(1) yield "huge success\n" make_server("localhost", 8000, myapp).serve_forever()
here, pass myapp
(the class) application callable - is. when request comes gets called, it's had written myapp(environ, start_response)
somewhere, __init__
starts , creates instance specific request. then, instance iterated, __iter__
starts produce response. after it's done, instance discarded.
basically, that's it. classes here convenience closures hold data. if don't need them, don't use classes, use plain functions - flat better nested.
now, code.
what code uses callable candy().app
. doesn't work because doesn't made receive environ
, start_response
passed. should fail 500 error, saying app() takes 1 positional arguments 3 given
.
i assume code in question modified after got nonetype has no attribute split
issue, , had passed __init__
when creating candy_instance = candy()
when __init__
still had 2 arguments (3 self
). not sure - should've failed earlier.
basically, passed wrong objects make_server
, class mix of 2 different ideas.
i suggest check examples above (and read pep-333), decide need, , structure candy
class that.
if need return on every request, , don't have persistent state - don't need class @ all.
if need persistent state (config, or, maybe, database connection) - use class instance,
__call__
method, , make__call__
return response.if need respond in chunks, use either generator function, or class
__iter__
method. or class__call__
yields
(just function).
hope helps.
Comments
Post a Comment