I have here a Python program.
It uses CherryPy to create a server.
# coding:utf-8
import os.path
import cherrypy
from app import application
def main():
try:
currentDir_s = os.path.dirname(os.path.abspath(__file__))
except:
currentDir_s = os.path.dirname(os.path.abspath(sys.executable))
cherrypy.Application.currentDir_s = currentDir_s
configFileName_s = 'server.conf'
if os.path.exists(configFileName_s) == False:
configFileName_s = None
cherrypy.engine.autoreload.unsubscribe()
cherrypy.engine.timeout_monitor.unsubscribe()
cherrypy.quickstart(application.Application_cl(), config=configFileName_s)
if __name__ == '__main__':
main()
And in "server.conf" it configure the server:
[global]
tools.log_headers.on: True
tools.sessions.on: False
tools.encode.on: True
tools.encode.encoding:"utf-8"
server.socket_port: 8080
server.socket_timeout:60
server.thread_pool: 10
server.environment: "production"
log.screen: True
[/]
tools.staticdir.root: cherrypy.Application.currentDir_s
tools.staticdir.on = True
tools.staticdir.dir = '.'
There is one thing, I don't understand, this line (line 13 in the python code):
cherrypy.Application.currentDir_s = currentDir_s
I searched in the internet about this, but I couldn't find anything. What does "cherrypy.Application" do? Why I have to do this assignment (cherrypy.Application.currentDir_s = currentDir_s)?
I searched the cherrypy source code and here is what I found.
In _cptree.py module you will find the Application class. Below that, there is a Tree class which has mount method which we are used to binding applications with (e.g. cherrypy.tree.mount(Root(), "/", config=config))
def mount(self, root, script_name="", config=None):
...
When you look inside this method you will see the code below;
def mount(self, root, script_name="", config=None):
...
if isinstance(root, Application):
app = root
if script_name != "" and script_name != app.script_name:
raise ValueError(
"Cannot specify a different script name and pass an "
"Application instance to cherrypy.mount")
script_name = app.script_name
else:
app = Application(root, script_name)
# If mounted at "", add favicon.ico
if (script_name == "" and root is not None
and not hasattr(root, "favicon_ico")):
favicon = os.path.join(os.getcwd(), os.path.dirname(__file__),
"favicon.ico")
root.favicon_ico = tools.staticfile.handler(favicon)
if config:
app.merge(config)
self.apps[script_name] = app
So, the code says that every object (application) you pass to the mount method is either Application instance or wrapped in an Application instance. So why is that so? When you check Application class above Tree class, you will see a __call__ method like below;
def __call__(self, environ, start_response):
return self.wsgiapp(environ, start_response)
Yes you see it now, it is wsgi interface.
Therefore, Application is a wsgi wrapper for your cherrypy applications.
When you check the source code of cherrypy you may learn lots of things. I hope this answer help you.
Related
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.
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 ;-)
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.
I've been thinking about ways to automatically setup configuration in my Python applications.
I usually use the following type of approach:
'''config.py'''
class Config(object):
MAGIC_NUMBER = 44
DEBUG = True
class Development(Config):
LOG_LEVEL = 'DEBUG'
class Production(Config):
DEBUG = False
REPORT_EMAIL_TO = ["ceo#example.com", "chief_ass_kicker#example.com"]
Typically, when I'm running the app in different ways I could do something like:
from config import Development, Production
do_something():
if self.conf.DEBUG:
pass
def __init__(self, config='Development'):
if config == "production":
self.conf = Production
else:
self.conf = Development
I like working like this because it makes sense, however I'm wondering if I can somehow integrate this into my git workflow too.
A lot of my applications have separate scripts, or modules that can be run alone, thus there isn't always a monolithic application to inherit configurations from some root location.
It would be cool if a lot of these scripts and seperate modules could check what branch is currently checked out and make their default configuration decisions based upon that, e.g., by looking for a class in config.py that shares the same name as the name of the currently checked out branch.
Is that possible, and what's the cleanest way to achieve it?
Is it a good/bad idea?
I'd prefer spinlok's method, but yes, you can do pretty much anything you want in your __init__, e.g.:
import inspect, subprocess, sys
def __init__(self, config='via_git'):
if config == 'via_git':
gitsays = subprocess.check_output(['git', 'symbolic-ref', 'HEAD'])
cbranch = gitsays.rstrip('\n').replace('refs/heads/', '', 1)
# now you know which branch you're on...
tbranch = cbranch.title() # foo -> Foo, for class name conventions
classes = dict(inspect.getmembers(sys.modules[__name__], inspect.isclass)
if tbranch in classes:
print 'automatically using', tbranch
self.conf = classes[tbranch]
else:
print 'on branch', cbranch, 'so falling back to Production'
self.conf = Production
elif config == 'production':
self.conf = Production
else:
self.conf = Development
This is, um, "slightly tested" (python 2.7). Note that check_output will raise an exception if git can't get a symbolic ref, and this also depends on your working directory. You can of course use other subprocess functions (to provide a different cwd for instance).
I need to store python code in a database and load it in some kind of bootstrap.py application for execution. I cannot use filesystem because I'm using GAE, so this is my only choice.
However I'm not a python experienced user.
I already was able to load 1 line of code and run it using eval, however a piece of code with two lines or more gave me a "invalid syntax" error.
I'm also thinking if it's possible to extend the "import" loader to implement the DB loading.
Thanks!
I was able to do what I intent after reading more about Python dynamic code loading.
Here is the sample code. I removed headers to be lighter:
Thanks anyway!
=============
class DynCode(db.Model):
name = db.StringProperty()
code = db.TextProperty(default=None)
=============
class MainHandler(webapp.RequestHandler):
def get(self):
dyn = DynCode()
dyn = "index"
dyn.code = """
from google.appengine.ext import webapp
class MainHandler(webapp.RequestHandler):
def get(self):
self.response.out.write("Hello World\\n")
self.response.out.write("Hello World 2\\n")
"""
dyn.put()
self.response.out.write("OK.")
def main():
application = webapp.WSGIApplication([('/update', MainHandler)], debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
==================================
def main():
query = DynCode.all()
dyncodes = query.fetch(1)
module = imp.new_module('mymodule')
for dyn in dyncodes:
exec dyn.code in module.__dict__
application = webapp.WSGIApplication([('/', module.MainHandler)], debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
=======================
If you want a more robust mechanism, you probably want to read PEP302, which describes input hooks. You can use these to import code rather than having to eval it.
I somewhat agree with the commentators above, it sounds kind of dangerous. However:
I experimented a little with App Engine Console ( http://con.appspot.com/console/ ), and eval() indeed tended to throw SyntaxError's.
Instead, the exec statement might be your friend ( http://docs.python.org/release/2.5.2/ref/exec.html ).
I managed to run this in App Engine Console:
>>> exec "def f(x):\n x = x + 1\n y = 10\n return x + y"
>>> f(10)
21
So try the exec statement, but remember the many, many (many!) perils of code coming directly from end-users.