Declaration of CherryPy Tool fails - python

I'm trying to declare a new tool to the CherryPy toolbox following the examples from the docs: Docs CherryPy Tools.
According to the examples I have written:
import cherrypy
def myTool():
print ("myTool")
class Root(object):
#cherrypy.expose
#cherrypy.tools.mytool()
def index(self):
return "Hello World!"
if __name__ == '__main__':
cherrypy.tools.mytool = cherrypy.Tool('before_finalize', myTool)
cherrypy.quickstart(Root(), '/')
This results in the following error:
Traceback (most recent call last):
File "server.py", line 6, in <module>
class Root(object):
File "server.py", line 8, in Root
#cherrypy.tools.mytool()
AttributeError: 'Toolbox' object has no attribute 'mytool'
However if I change the notation to the following it works as expected.
import cherrypy
def myTool():
print ("myTool")
class Root(object):
#cherrypy.expose
def index(self):
return "Hello World!"
index._cp_config = {'tools.mytool.on': True}
if __name__ == '__main__':
cherrypy.tools.mytool = cherrypy.Tool('before_finalize', myTool)
cherrypy.quickstart(Root(), '/')
The docs says that both methods have the same effect, but not in my case. If anyone knows what I'm doing wrong I'll be very grateful.
The tool should not be defined globally, hence the #cherrypy.tools.mytool() notation.
I'm using python 3.6.

The problem is the misunderstanding of the evaluation order of python (top-down), at the time the class is defined the tool has not been defined.
You can define the tool in another file import at the top (before the class definition) and it should work.
The second form works, because the configuration is done indirectly using strings in the config, not the real tool objects.

Related

Trouble with injecting Callable

I'm using python-dependency-injector.
I tried this code and it worked perfectly:
https://python-dependency-injector.ets-labs.org/providers/callable.html
that page also mentioned next:
Callable provider handles an injection of the dependencies the same way like a Factory provider.
So I went and wrote this code:
import passlib.hash
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Container(containers.DeclarativeContainer):
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
#inject
def bar(password_verifier=Provide[Container.password_verifier]):
pass
if __name__ == "__main__":
container = Container()
container.wire(modules=[__name__])
bar()
And it -- as you might expect -- didn't work. I received this error:
Traceback (most recent call last):
File "/home/common/learning_2022/code/python/blog_engine/test.py", line 20, in <module>
bar()
File "src/dependency_injector/_cwiring.pyx", line 26, in dependency_injector._cwiring._get_sync_patched._patched
File "src/dependency_injector/providers.pyx", line 225, in dependency_injector.providers.Provider.__call__
File "src/dependency_injector/providers.pyx", line 1339, in dependency_injector.providers.Callable._provide
File "src/dependency_injector/providers.pxd", line 635, in dependency_injector.providers.__callable_call
File "src/dependency_injector/providers.pxd", line 608, in dependency_injector.providers.__call
TypeError: GenericHandler.verify() missing 2 required positional arguments: 'secret' and 'hash'
I ran into this problem too and after much search I found the answer.
You can inject the callable by using the provider attribute:
import passlib.hash
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Container(containers.DeclarativeContainer):
# Use the 'provider' attribute on the provider in the container
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify).provider
#inject
def bar(password_verifier=Provide[Container.password_verifier]):
password_verifier(...)
if __name__ == "__main__":
container = Container()
container.wire(modules=[__name__])
bar()
The method passlib.hash.sha256_crypt.verify requires two positional arguments, secret and hash as shown here: https://passlib.readthedocs.io/en/stable/lib/passlib.hash.sha256_crypt.html
Because you're injecting an attribute of the Container, the DI framework must create an instance of this to inject it into the bar() method. The DI framework is unable to instantiate this object however since the required positional arguments are missing.
If you wanted to use the method in bar(), you'd have to do so without provoking the DI framework to try to create an instance of the object at initialisation time. You could do this with the following:
import passlib.hash
from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject
class Container(containers.DeclarativeContainer):
password_hasher = providers.Callable(
passlib.hash.sha256_crypt.hash,
salt_size=16,
rounds=10000,
)
password_verifier = providers.Callable(passlib.hash.sha256_crypt.verify)
#inject
def bar(container=Provide[Container]):
hashed_password = container.password_hasher("123")
assert container.password_verifier("123", hashed_password)
if __name__ == "__main__":
container = Container()
container.wire(modules=[__name__])
bar()

attributeError for #classmethod generated when python script is imported into another script but not when tested stand alone

I am trying to re-use some code from the CoderBot project to build my own web controlled robot.
I am using python3 on a raspberry PI and I have simplified the code just to generate the error.
'''
class myclass():
objClass = None
def init(self):
print("initialised")
#classmethod
def get_it(cls):
if not cls.objClass:
print("objClass does not exist")
cls.objClass = myclass()
print("created")
return cls.objClass
def main(args):
method_list = [method for method in dir(myclass) if method.startswith('_') is False]
print(method_list)
makeone = myclass.get_it()
print(makeone)
print(myclass.get_it())
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
'''
when I run this the following output is produced
'''
['get_it', 'objClass']
objClass does not exist
initialised
created
<__main__.myclass object at 0x7fbe6e1fa0>
<__main__.myclass object at 0x7fbe6e1fa0>
'''
Everything is as I expected.
When I run this code in a separate script
'''
import ct
def main(args):
method_list = [attribute for attribute in dir(ct.myclass) if
callable(getattr(ct.myclass, attribute)) and attribute.startswith('__') is
False]
print(method_list)
two = ct.get_it()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
'''
The following output is produced:
'''
['get_it']
Traceback (most recent call last):
File "/home/pi/classTest/mainct.py", line 35, in <module>
sys.exit(main(sys.argv))
File "/home/pi/classTest/mainct.py", line 30, in main
two = ct.get_it()
AttributeError: module 'ct' has no attribute 'get_it'
'''
This output is telling me that 'get_it' exists in the class, but not when I try and create one.
I am very confused and have looked at lots of tutorials but can't spot what I am doing wrong.
It is probably one of those errors where if I sat down and spoke to someone it would be obvious, but I can't spot it!
Steve
PS I hope the formatting is ok,
As jasonharper said, I was not referencing the class!
When I went back and looked at the original code I had not spotted the change in case.
so with my example the class MyClass should have been defined in a file myclass.py and then referenced as
from myclass import MyClass
then in the code
two = MyClass.get_it()
I have hopefully sorted out the formatting, the post was originally created on my PI and I spent 40 minutes trying to format it correctly.
This problem is definitely closed, thanks for replies
Is "ct" your class?
two = ct()
two.get_it()

Dynamically call function from another file in python while in runtime using flask

I would like to use flask to run some functions. Assume you have a file called myapp.py with a function run
def run():
return 'special routed hello world'
and this main flask file, something like this
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'hello world'
#app.route('/<myapp>')
def open_app(myapp):
from myapp import run
return run()
So obvisouly that doesn't work, but how can I dynamically call these run functions when flask is already running. Is this even possible?
In other words: when someone opens for example .../foobar, the function open_app with parameter foobar is begin called. In that function, from the file foobar.py (let's assume that file exists) import function run, run it and return the result from that function.
In fact, it is possible to use importlib, especially import_modulein combination with getattr, to dynamically call up functions of a module. And I have security concerns too.
The following two examples show a kind of simple RPC implementation.
The first example uses a dictionary for modules. If a module with the name is available, the run function is called. It allows a strong restriction. Optimization is certainly possible and probably necessary.
The second example shows a possibility of calling different functions within different modules with parameters. In spite of everything, as with the previous version, all modules are in one package called "actions" to ensure that calls can be limited. I also think a variant with POST is more suitable for this purpose than using variable rules.
Remember these are strong simplifications. Protocols such as JSON-RPC will certainly help as a guide during implementation.
from flask import Flask
from flask import jsonify, request, jsonify
from importlib import import_module
from actions import *
app = Flask(__name__)
app.secret_key = 'your secret here'
#app.route('/exec/<string:action>', methods=['POST'])
def exec(action):
result = cmddict[action].run()
return jsonify(result=result)
#app.route('/call', methods=['POST'])
def call():
data = request.get_json()
module = data.get('module')
method = data.get('method')
params = data.get('params')
try:
# import module by name
m = import_module(f'actions.{module}', __name__)
# get function by name
f = getattr(m, method)
# call function with params
result = f(**params) if isinstance(params, dict) else f(*params)
return jsonify(result=result, error=None)
except Exception as err:
return jsonify(result=None, error=f'{err}')
# ./actions/__init__py
__all__ = ['demo']
from importlib import import_module
cmddict = {}
for _ in __all__:
cmddict[_] = import_module(f'actions.{_}', __name__)
__all__.append('cmddict')
# ./actions/demo.py
def run():
return f'hello world'
def func(*args, **kwargs):
print('func', args, kwargs)
``

How to start Bottle as a daemon from another script?

I would like to use BottlePy as a daemon started from another script and I have issues turning a standalone script (webserver.py) into a class. The standalone version of my webserver below works fine:
import bottle
#bottle.get('/hello')
def hello():
return 'Hello World'
#bottle.error(404)
def error404(error):
return 'error 404'
bottle.run(host='localhost', port=8080)
My intent is now to start it from the main script below as
from webserver import WebServer
from multiprocessing import Process
def start_web_server():
# initialize the webserver class
WebServer()
# mainscript.py operations
p = Process(target=start_web_server)
p.daemon = True
p.start()
# more operations
where WebServer() would be in the naively now-modified webserver.py:
import bottle
class WebServer():
def __init__(self):
bottle.run(host='localhost', port=8080)
#bottle.get('/hello')
def hello(self):
return 'Hello World'
#bottle.error(404)
def error404(self, error):
return 'error 404'
What works: the whole thing starts and the webserver is listening
What does not work: upon calling http://localhost:8080/hello
127.0.0.1 - - [11/Dec/2013 10:16:23] "GET /hello HTTP/1.1" 500 746
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\bottle.py", line 764, in _handle
return route.call(**args)
File "C:\Python27\lib\site-packages\bottle.py", line 1575, in wrapper
rv = callback(*a, **ka)
TypeError: hello() takes exactly 1 argument (0 given)
My questions are:
what kind of parameters am I expected to pass to hello() and error404()?
what should I do in order to parametrize #bottle.get('/hello')? I would like to have something like #bottle.get(hello_url) but where should hello_url = '/hello' be initialized? (self.hello_url is unknown to #bottle.get)
EDIT: while preparing a fork of this question to handle question 2 (about the parametrization) I had an epiphany and tried the obvious solution which works (code below). I am not that used to classes yet so I did not have the reflex to add the variable in the scope of the class.
# new code with the path as a parameter
class WebServer():
myurl = '/hello'
def __init__(self):
bottle.run(host='localhost', port=8080, debug=True)
#bottle.get(myurl)
def hello():
return 'Hello World'
#bottle.error(404)
def error404(error):
return 'error 404'
what kind of parameters am I expected to pass to hello() and error404()?
The short answer: none. Just remove self and they should start to work.
#bottle.get('/hello')
def hello():
return 'Hello World'
#bottle.error(404)
def error404(error):
return 'error 404'
what should I do in order to parametrize #bottle.get('/hello')? I
would like to have something like #bottle.get(hello_url) but where
should hello_url = '/hello' be initialized? (self.hello_url is unknown
to #bottle.get)
I can interpret this a couple of different ways, so I'm not sure how to help you. But since this is a completely separate question (with potentially a much larger scope), please consider asking it in a new, separate SO question.

How do you call class methods in a signal handler in python daemon?

I'm trying to write a signal handler that will call methods from a class variable.
I have code that looks like this:
import daemon
class bar():
def func():
print "Hello World!\n"
def sigusr1_handler(signum,frame):
foo.func()
def main():
foo = bar()
context = daemon.DaemonContext(stdout=sys.stdout)
context.signal_map = {
signal.SIGUSR1: sigusr1_handler
}
with context:
if (__name__="__main__"):
main()
This doesn't work. Python throws a NameError exception when I do a kill -USR1 on the daemon.
I also tried defining functions inside main that would handle the exception and call those functions from the signal handlers, but that didn't work either.
Anybody have ideas on how to implement this?
One option would be to import class bar inside your sigusr1_handler function. It's probably a good idea to have it in a different file anyway
Do you import signal? Because if I run you code I get:
Traceback (most recent call last):
File "pydaemon.py", line 16, in <module>
signal.SIGUSR1: sigusr1_handler
NameError: name 'signal' is not defined
You might fix this with:
import signal
And have a look at your string comparison oparator
with context:
if (__name__="__main__"):
main()
I generally use the '==' operator instead of '='

Categories