When is sys.stdin None in Python? - python

I'm trying to run Flask as a simple CGI app through IIS.
I have the following code:
from wsgiref.handlers import CGIHandler
from flask import Flask
app = Flask(__name__)
#app.route('/')
def main():
return 'Woo woo!'
CGIHandler().run(app)
I'm runing Python 3.3 on Windows. I get the following error:
File "C:\Python33\lib\wsgiref\handlers.py",
line 509, in __init__(self, sys.stdin.buffer, sys.stdout.buffer, sys.stderr, )
AttributeError: 'NoneType' object has no attribute 'buffer' ".
I added some logging code, and it turns out that sys.stdin is None.
Python is added to IIS as a CGI Handler as follows:
Request path: *.py
Executable: C:\Windows\py.exe -3 %s %s
So, why is sys.stdin None, and how can I fix it?
EDIT
It looks like sys.stdin is None because the file descriptor is invalid.

Interesting. You've answered half your own question. The other half ("how do I fix it") is easy enough, just open some suitable thing (os.devnull is the obvious one) and set sys.stdin to point there. You'll need to do sys.stdout and sys.stderr as well, presumably, so something like this:
import os, sys
for _name in ('stdin', 'stdout', 'stderr'):
if getattr(sys, _name) is None:
setattr(sys, _name, open(os.devnull, 'r' if _name == 'stdin' else 'w'))
del _name # clean up this module's name space a little (optional)
from wsgiref.handlers ...
should do the trick.

Related

How to stop cherrypy auto-reload from changing the process name on Debian?

I am developing a project using cherrypy, on debian. At my work, the administrators want to see the name of the project instead of "python" displayed when using commands like ps -e. However, when cherrypy auto-reloads when modifying one source file, it automatically changes the process name.
For example, if I take the most basic cherrypy tutorial and save it under NameToSee.py:
#!/usr/bin/python
import cherrypy
class HelloWorld(object):
#cherrypy.expose
def index(self):
return "Hello world!"
if __name__ == '__main__':
cherrypy.quickstart(HelloWorld())
By adding the shebang at the start, when I launch it $ ./NameToSee.py &, I get a process (say 31051) whose name is "NameToSee.py":
$ head /proc/31051/status
Name: NameToSee.py
State: S (sleeping)
However, whenever I change the source code files (for example, by adding an empty line), the process name changes:
$ head /proc/31051/status
Name: python
State: S (sleeping)
So, my question is: Can I get both cherrypy auto-reload and custom process name ? If not, can I remove the cherrypy auto-reload?
I am running on debian wheezy, with python 2.7.3 and cherrypy 3.2.2
This sample covers both cases:
import cherrypy
from cherrypy.process.plugins import SimplePlugin
PROC_NAME = 'sample'
def set_proc_name(newname):
"""
Set the process name.
Source: http://stackoverflow.com/a/923034/298371
"""
from ctypes import cdll, byref, create_string_buffer
libc = cdll.LoadLibrary('libc.so.6')
buff = create_string_buffer(len(newname)+1)
buff.value = newname
libc.prctl(15, byref(buff), 0, 0, 0)
class NamedProcess(SimplePlugin):
"""
Set the name of the process everytime that the
engine starts.
"""
def start(self):
self.bus.log("Setting the name as '{}'".format(PROC_NAME))
set_proc_name(PROC_NAME)
class HelloWorld(object):
#cherrypy.expose
def index(self):
return "Hello world!"
def run_without_autoreload():
set_proc_name(PROC_NAME)
cherrypy.quickstart(HelloWorld(), config={
'global': {
'engine.autoreload.on': False
}
})
def run_with_autoreload():
# Work on any configuration but for the sake of the
# question this works with the autoreload.
NamedProcess(cherrypy.engine).subscribe()
cherrypy.quickstart(HelloWorld())
if __name__ == '__main__':
run_with_autoreload()
# run_without_autoreload()
You can test it with:
cat /proc/`pgrep sample`/status
(or maybe just use pgrep)
And as a final recommendation consider using the "production" environment (see the docs) which also included the disabling of the autoreload plugin.

Default the root view in cherrypy

In some source code I am
writing, I am able to make a request such as:
http://proxy.metaperl.org/index/bitgold-rw1
And have it redirect successfully.
However, I want to remove index from the URL and have it still
redirect by using the index() method. I tried renaming index() to
default() after reading about
Dispatching,
but it still does not allow me to have a URL like this:
http://proxy.metaperl.org/bitgold-rw1
It tries to find a method named bitgold-rw1 instead of using the
default method to resolve the request, gving me the error:
NotFound: (404, "The path '/bitgold-rw1' was not found.")
The WSGI startup file looks like this:
# -*- python -*-
# core
import os
import sys
# 3rd party
import cherrypy
# local
def full_path(*extra):
return os.path.join(os.path.dirname(__file__), *extra)
sys.path.insert(0, full_path())
import config
import myapp
application = cherrypy.Application(
myapp.Root(),
"/",
config.config)
As mentioned by #ralhei #saaj default method is the key if you do not want to deal with dispatchers in cherrypy. I tried the code below and working as you want
class Root(object):
#cherrypy.expose
def index(self, tag):
redirect_url = db.urls[tag]
ip = cherrypy.request.headers['Remote-Addr']
request_url = 'http://ipinfo.io/{0}/country'.format(ip)
r = requests.get(request_url)
country = r.text.strip()
raise cherrypy.HTTPRedirect(redirect_url)
#cherrypy.expose
def default(self,tag):
return self.index(tag)
Renaming to default is not enough. It needs to be callable at least with variadic arguments, *args, to receive path segments. Like this:
#!/usr/bin/env python3
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class Root:
#cherrypy.expose
def default(self, *args, **kwargs):
cherrypy.log('{0}, {1}'.format(args, kwargs))
return 'OK'
if __name__ == '__main__':
cherrypy.quickstart(Root(), '/', config)
Then it will catch things like http://127.0.0.1:8080/bitgold-rw1/ and also like http://127.0.0.1:8080/bitgold-rw1/foo/bar.
And btw, if it's about MVC it's a controller, not a view.
if you rename your index method to 'default' in your Root class this should work.
Add the line
cherrypy.quickstart(Root())
at the bottom of myapp.py and run it with 'python myapp.py' your server should startup and listen on port 8080.
Making a request to http://localhost:8080/bitgold-rw1 works for me, it complains that I'm not a US citizen which I guess is fine ;-)

Why are environment variables empty in Flask apps?

I have a flask app (my_app) that calls a function in a different file (my_function):
my_app.py:
from my_functions import my_function
#app.route('/')
def index():
my_function()
return render_template('index.html')
my_functions.py:
def my_function():
try:
import my_lib
except:
print("my_lib not found in system!")
# do stuff...
if __name__ == "__main__":
my_function()
When I execute my_functions.py directly (i.e., python my_functions.py) "my_lib" is imported without error; however, when I execute the flask app (i.e., python my_app.py) I get an import error for "my_lib".
When I print the LD_LIBRARY_PATH variable at the beginning of each file:
print(os.environ['LD_LIBRARY_PATH'])
I get the correct value when calling my_functions.py, but get no value (empty) when calling my_app.py.Trying to set this value at the beginning of my_app.py has no effect:
os.environ['LD_LIBRARY_PATH'] = '/usr/local/lib'
Questions:
(1) Why is 'LD_LIBRARY_PATH' empty when called within the Flask app?
(2) How do I set it?
Any help appreciated.
LD_LIBRARY_PATH is cleared when executing the flask app, likely for security reasons as Mike suggested.
To get around this, I use subprocess to make a call directly to an executable:
import subprocess
call_str = "executable_name -arg1 arg1_value -arg2 arg2_value"
subprocess.call(call_str, shell=True, stderr=subprocess.STDOUT)
Ideally the program should be able to use the python bindings, but for now calling the executable works.

Why do I get an error trying to install my Python service in Windows?

Ok, so I wrote a python service that simply writes to a file. I packaged it all up with cx_freeze, and installed it as a Service via the command prompt. It ran fine, but then I realized that the file it was to writing was in some weird directory, so I changed the service code to write the file to my documents. Here's the code for my Python Service:
import win32service
import win32serviceutil
import win32event
class PySvc(win32serviceutil.ServiceFramework):
_svc_name_ = "PySvc"
_svc_display_name_ = "Python Test Service"
_svc_description_ = "This is a service that simply writes to a file"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcDoRun(self):
import servicemanager
f = open('C:/Users/Luke/Documents/test.dat', 'w+')
rc = None
while rc != win32event.WAIT_OBJECT_0:
f.write('TEST DATA\n')
f.flush()
rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)
f.write('SHUTTING DOWN...\n')
f.close()
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
if __name__ == '__main':
win32serviceutil.HandleCommandLine(PySvc)
This line:
f = open('C:/Users/Luke/Documents/test.dat', 'w+')
Used to look like this (when it worked):
f = open('test.dat', 'w+')
This was the only change that I made to the code.
This time when I attempted to install it in the cmd, it returned this frustrating error:
Exception occurred while initializing the installation:System.BadImageFormatException: Could not load file or assembly 'file:///C:\PySvc\PySvc.exe' or one of its dependencies. The module was expected to contain an assembly manifest..
What Happened? Any Help?
I found the solution, and realized how amateur I truly am. Somewhere along the way, I accidently deleted the last 2 '_'s in if __name__ == '__main__': as you can see in the code. Just goes to show you that you should check all your code before you ask a SO question! So I changed this:
if __name__ == '__main':
To this:
if __name__ == '__main__':

Python - asyncore.dispatcher module error

I started learning this asyncore.dispatcher module and when I run the first example program it gives the error as per below:
Python version 2.6
asyncore module is installed and there is also dispatcher class inside it. What may be the problem !
Error:
AttributeError: 'module' object has no attribute 'dispatcher'
Example code:
import asyncore, socket
class HTTPClient(asyncore.dispatcher):
def __init__(self, host, path):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect( (host, 80) )
self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path
def handle_connect(self):
pass
def handle_close(self):
self.close()
def handle_read(self):
print self.recv(8192)
def writable(self):
return (len(self.buffer) > 0)
def handle_write(self):
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
client = HTTPClient('www.python.org', '/')
asyncore.loop()
Your problem is that you named your file asyncore.py. It's shadowing the asyncore.py in the python standard lib so the file is importing itself instead of the real one. You want to rename your copy of the file and delete asyncore.pyc in the same directory if it exists. Then when you run your file, you'll be importing the asyncore.py from the standard library.
When Python runs the line import asyncore, python looks through the directories in sys.path for a file named asyncore.py. The directory of the primary file that's executing is always the first entry in it. So Python finds your file and attempts to import it. As a general rule, you should never give your files the same name as a module from the standard library if you want to use that module.

Categories

Resources