Any suggestion toward a clean solution will be appreciated.
I am trying to add some static files to an existing app, a static folder with other files is already set. I would like to define several routes based on a list, the goal is to be able to easily add files.
The problem is that I receive this instead of a working program, the "endpoint function" isn't properly detected.
Output:
{'/file1.js': <function func at 0x10aedfed8>, '/file2.js': <function func at 0x10aeea050>}
{'/file1.js': <function func at 0x10aedfed8>, '/file2.js': <function func at 0x10aeea050>}
Traceback (most recent call last):
File "flaskweird.py", line 29, in <module>
app.add_url_rule(d, '', app.serv_deps[d])
File "/Library/Python/2.7/site-packages/flask/app.py", line 62, in wrapper_func
return f(self, *args, **kwargs)
File "/Library/Python/2.7/site-packages/flask/app.py", line 984, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function:
Code :
from flask import Flask
app = Flask(__name__)
def gen_serv_dep(path):
fp = 'ui' + path # path always starts with /
with open(fp) as f:
content = f.read()
if path.endswith('.css'):
mime = "text/css"
elif path.endswith('.js'):
mime = "text/javascript"
else:
mime = "text"
def func():
#this.__name__ = path # doesn't change anything
return Response(response=content, status=200, mimetype=mime)
return func
deps = ['/file1.js', '/file2.js']
app.serv_deps = {}
for d in deps:
app.serv_deps[d] = gen_serv_dep(d)
for d in deps:
print(app.serv_deps)
app.add_url_rule(d, '', app.serv_deps[d])
#app.route('/')
def hello_world():
return 'Hello, World!'
Sample files to serve:
mkdir ui
echo "test1" > ui/file1.js
echo "test2" > ui/file2.js
Flask==0.10.1
"Because you passed an empty string to add_url_rule multiple times in a for loop. Pick a unique name each time." -- davidism
This works fine
for d in deps:
app.add_url_rule(d, d, app.serv_deps[d])
Thanks
Related
I have recently changed my main flask app file from inputServer.py to app.py to increase ease of use.
My code that throws the error is as follows:
def readBackupPlayers(objectFile):
with open(objectFile, 'rb') as openedFile:
manager.playerList = pickle.load(openedFile)
print('Backup of players retrieved')
^
Function that read a custom pickle file used for backing up a list stored inside a custom object
class PlayerManager:
def __init__(self):
self.playerList = []
self.ID = len(self.playerList) + 1
self.currentGame = None
self.tournament = None
manager = PlayerManager()
^
Code that declares the class and creates an instance of it to use to store variables across the program.
Error message:
File "c:\users\simon\appdata\local\programs\python\python38-32\lib\site-packages\flask\app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\simon\OneDrive\Documents\AtomTesting\app.py", line 356, in setup
readBackupPlayers('Backups/playerBackup')
File "C:\Users\simon\OneDrive\Documents\AtomTesting\app.py", line 72, in readBackupPlayers
manager.playerList = pickle.load(openedFile)
ModuleNotFoundError: No module named 'inputServer'
Directory:
AtomTesting -
Backups -
playerBackup
tournamentBackup
Static -
static Flask files (not relevant)
templates -
Flask templates (not relevant)
app.py (renamed from inputServer.py)
config.py
README.md
Here's what's happening. Python's pickle module serializes and deserializes (dumps and loads) Python objects based on their name. Since the name of the module where your class lives changed, Pickle can't figure out how to re-instanciate those objects.
There is, however, a solution which is detailed on the Python wiki. It involves mapping old names to new names:
import pickle
renametable = {
'inputServer': 'app',
}
def mapname(name):
if name in renametable:
return renametable[name]
return name
def mapped_load_global(self):
module = mapname(self.readline()[:-1])
name = mapname(self.readline()[:-1])
klass = self.find_class(module, name)
self.append(klass)
def loads(str):
file = StringIO(str)
unpickler = pickle.Unpickler(file)
unpickler.dispatch[pickle.GLOBAL] = mapped_load_global
return unpickler.load()
Alternatively, and this is probably a better approach, you shouldn't use pickle for any serious data store, especially when something might be used between versions of your app.
You might consider using an ORM with a lightweight database, like SQLite.
I am trying my hand at serverless deployment of an API... and getting annoyingly stuck at the setup stage.
I'm trying to run zappa init from cmd, but I am getting a weird error.
The command actually worked the first time I ran it (I cancelled at the last step, realizing I wanted to setup my S3 bucket first).
When I tried it again, after installing and configuring awscli, then installing flask to my virtual environment, I got the following error:
Your Zappa deployments will need to be uploaded to a private S3 bucket.
If you don't have a bucket yet, we'll create one for you too.
What do you want call your bucket? (default 'zappa-hohr3kxh7'):
It looks like this is a Flask application.
Oh no! An error occurred! :(
==============
Traceback (most recent call last):
File "c:\users\joshu\documents\code\machine-learning\boston-housing-price\app\env\venv\lib\site-packages\zappa\cli.py", line 2610, in handle
sys.exit(cli.handle())
File "c:\users\joshu\documents\code\machine-learning\boston-housing-price\app\env\venv\lib\site-packages\zappa\cli.py", line 476, in handle
self.init()
File "c:\users\joshu\documents\code\machine-learning\boston-housing-price\app\env\venv\lib\site-packages\zappa\cli.py", line 1604, in init
matches = detect_flask_apps()
File "c:\users\joshu\documents\code\machine-learning\boston-housing-price\app\env\venv\lib\site-packages\zappa\utilities.py", line 143, in detect_flask_apps
lines = f.readlines()
File "c:\users\joshu\documents\code\machine-learning\boston-housing-price\app\env\venv\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 301: character maps to <undefined>
I'm running Windows 10, Python 3.6 Anaconda distribution.
Most of my code lies in an api.py file, other than that there is an index.html file. Here's the api.py code:
from flask import Flask, render_template, request, jsonify
from sklearn.externals import joblib
import boto3
import numpy as np
import pickle
app = Flask(__name__)
BUCKET_NAME = 'ml-boston-housing'
MODEL_FNAME = 'model.pkl'
S3 = boto3.client('s3', region_name='us-east-1')
# memoized annotation, caches model file after it's pulled
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#app.route('/')
#app.route('/index')
def index():
return render_template('index.html')
#app.route('/predict', methods=['POST'])
def make_prediction():
if request.method == 'POST':
app.logger.info("{} request received from: {}".format(
request.method, request.remote_addr))
mdl = load_model(MODEL_FNAME)
input_data = np.zeros((1, 13))
if request.json or 'data' in request.json:
for i, k in enumerate(request.get_json()):
input_data[0, i] = request.form.get(k, 0)
result = np.squeeze(mdl.predict(input_data))
return jsonify({'result': result})
else:
for i, k in enumerate(request.form.keys()):
input_data[0, i] = request.form.get(k, 0)
result = np.squeeze(mdl.predict(input_data))
return render_template('index.html', label=result)
#memoize
def load_model(key):
response = S3.get_object(Bucket=BUCKET_NAME, Key=key)
modelstr = response['Body'].read()
model = pickle.load(modelstr)
return model
if __name__ == '__main__':
app.run(host='0.0.0.0')
Kind of figured it out, when Zappa init runs, it calls def detect_flask_apps() function in the utilities.py file. This function reads each python file in the project directory, including the libraries in the virtual environment folder.
There is a library called functools.py that must have different character encodings than what is the default, because
with open(full, 'r') as f:
lines = f.readlines()
fails when reading ~/env/venv/Lib/functools.py.
The fix is to specify the encoding:
with open(full, 'r', encoding='utf-8') as f:
lines = f.readlines()
in zappa/utilities.py -- line 148
I followed this link : "https://pypi.python.org/pypi/bottle-mysql/0.1.1"
and "http://bottlepy.org/docs/dev/"
this is my py file:
import bottle
from bottle import route, run, template
import bottle_mysql
app = bottle.Bottle()
# # dbhost is optional, default is localhost
plugin = bottle_mysql.Plugin(dbuser='root', dbpass='root', dbname='delhipoc')
app.install(plugin)
#route('/hai/<name>')
def show(name,dbname):
dbname.execute('SELECT id from poc_people where name="%s"', (name))
print "i am in show"
return template('<b>Hello {{name}}</b>!',name=name)
run(host='localhost', port=8080)
this is my code and it is throwing error like:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\bottle.py", line 764, i
return route.call(**args)
File "C:\Python27\lib\site-packages\bottle.py", line 1575,
rv = callback(*a, **ka)
TypeError: show() takes exactly 2 arguments (1 given)
please help me
Not familiar with bottle-mysql, but in the example you provided:
#app.route('/show/:<tem>')
In your code:
#route('/hai/<name>')
It might expect:
#route('/hai/:<name>')
Simple. Change this line:
def show(name,dbname):
to this:
def show(name, delhipoc):
Better yet, use dbname = 'db' and then
def show(name, db):
The MySQL plugin has chosen an unfortunate name for its db name param. It would've been more clear to call it something like db_parameter_name, because what it actually refers to is the name of the db parameter in the decorated Python function.
I'm tying to use Cherrypy for a website, but I have some problem with mapping the url of the page I want to display with function in the python code.
Now I have this code
#!/usr/bin/env python
import os
localDir = os.path.dirname(__file__)
absDir = os.path.join(os.getcwd(), localDir)
import cherrypy
from genshi.template import TemplateLoader
loader = TemplateLoader('../html', auto_reload=True)
class Root(object):
#cherrypy.expose
def index(self):
tmpl = loader.load('index.html')
return tmpl.generate().render('html', doctype='html')
#cherrypy.expose
def upload(self, datafile):
#do something
...
return out % (size, datafile.filename, datafile.content_type)
cherrypy.root.index = index
cherrypy.root.upload = upload
conf = os.path.join(os.path.dirname(__file__), 'server.config')
cherrypy.quickstart(Root(), '/', config=conf)
And the configuration file is this:
[/index.html]
tools.staticfile.on = True
tools.staticfile.filename = "/path-to-file/html/index.html"
[/impemails.html]
tools.staticfile.on = True
tools.staticfile.filename = "/path-to-file/html/impemails.html"
[/css/style.css]
tools.staticfile.on = True
tools.staticfile.filename = "/path-to-file/css/style.css"
[/css/index.css]
tools.staticfile.on = True
tools.staticfile.filename = "/path-to-file/css/index.css"
[/css/imp.css]
tools.staticfile.on = True
tools.staticfile.filename = "/path-to-file/css/imp.css"
For all the file specified in the configuration file there are no problem, but when I try to access upload with the link http://localhost:8080/upload I get the "404 Not found Message"
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/cherrypy/_cprequest.py", line 656, in respond
response.body = self.handler()
File "/usr/local/lib/python2.7/dist-packages/cherrypy/lib/encoding.py", line 188, in __call__
self.body = self.oldhandler(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/cherrypy/_cperror.py", line 386, in __call__
raise self
NotFound: (404, "The path '/upload' was not found.")
I tried many different ways to solve this problem as shown in the tutorial http://docs.cherrypy.org/dev/concepts/dispatching.html but I failed.
I think I'm missing some configurations which are not reported in the tutorial.
Anybody as some ideas?
Thank you in advance
My bad, I misunderstood some configurations.
I've solved with this:
class Root(object):
#cherrypy.expose
def index(self):
tmpl = loader.load('index.html')
return tmpl.generate().render('html', doctype='html')
#cherrypy.expose
def upload(couchdb, maillist, datafile):
return "upload file"
conf = os.path.join(os.path.dirname(__file__), 'server.config')
root = Root()
root.upload = upload
cherrypy.tree.mount(root, '/', config=conf)
cherrypy.engine.start()
cherrypy.engine.block()
Basically I've just moved the function outside the Root class and added the path with root.upload = upload
Now it works.
I'm trying to set up a simple way of decorating methods in my CherryPy controller classes so that a user is redirected to the login page if they haven't authenticated yet. I was going to do a basic Python decorator, but an answer here suggested I use a CherryPy Custom Tool instead. So I'm trying to do that, but I can't get it to work. Here's what I have:
def authenticate():
user = cherrypy.session.get('user', None)
if not user:
raise cherrypy.HTTPRedirect('/?errMsg=Please%20log%20in%20first')
cherrypy.tools.authenticate = cherrypy.Tool('on_start_resource', authenticate)
The /home page is a page that should be restricted to authenticated users, so I have this:
#cherrypy.expose
#cherrypy.tools.authenticate
def home(self, **kwargs):
tmpl = TemplateDir.get_template('home.mako')
return tmpl.render()
However, I get this error when I try to start my web site:
Traceback (most recent call last):
File ".\example.py", line 3, in <module>
from controller.main import Root
File "C:\...\controller\main.py", line 9, in <module>
class Root(BaseModule):
File "C:\...\controller\main.py", line 19, in Root
#cherrypy.tools.authenticate
File "C:\Python26\lib\site-packages\cherrypy\_cptools.py", line 119, in
__call__ % self._name)
TypeError: The 'authenticate' Tool does not accept positional arguments; you must
use keyword arguments.
Edit: okay, if I change my use of the custom tool to have parentheses, I get a different error.
#cherrypy.expose
#cherrypy.tools.authenticate() # Magic parentheses...
def home(self, **kwargs):
...
Now I get:
Traceback (most recent call last):
File "C:\Python26\lib\site-packages\cherrypy\_cprequest.py", line 625, in respond
self.hooks.run('on_start_resource')
File "C:\Python26\lib\site-packages\cherrypy\_cprequest.py", line 97, in run
hook()
File "C:\Python26\lib\site-packages\cherrypy\_cprequest.py", line 57, in __call__
return self.callback(**self.kwargs)
File ".\example.py", line 40, in authenticate
user = cherrypy.session.get('user', None)
AttributeError: 'module' object has no attribute 'session'
Edit: I have sessions turned on:
cherrypy.tools.sessions.storage_type = 'file'
cherrypy.tools.sessions.storage_path = r'%s\sessions' % curDir
cherrypy.tools.sessions.timeout = 60
cherrypy.tree.mount(Root(), "/", config={
'/static': {
'tools.staticdir.on':True,
'tools.staticdir.dir':r'%s\static' % curDir,
},
'/': {
'tools.sessions.on':True,
}
})
When I first load the page with my custom tool decorator on the web method, I get this error:
AttributeError: 'module' object has no attribute 'session'
Then when I reload the page, I get this error:
AttributeError: '_Serving' object has no attribute 'session'
Edit: even trying this much in my controller class, I still get the 'module object has no attribute session' error:
class Root(BaseModule):
_cp_config = {'tools.sessions.on': True}
sess = cherrypy.session # Error here
...
I was using the wrong hook. Changing:
cherrypy.tools.authenticate = cherrypy.Tool('on_start_resource', authenticate)
To:
cherrypy.tools.authenticate = cherrypy.Tool('before_handler', authenticate)
Fixed the problem. Apparently my authenticate method was getting called before sessions had been turned on, so it couldn't access cherrypy.session. I didn't need any session-turn-on stuff in my controllers; all that was necessary was the following in my server-start script:
def authenticate():
...
cherrypy.tools.authenticate = cherrypy.Tool('before_handler', authenticate)
cherrypy.tree.mount(Root(), "/", config={
"/": {
'tools.sessions.on':True,
'tools.sessions.storage_type':'file',
'tools.sessions.storage_path':r'%s\sessions' % curDir,
'tools.sessions.timeout':60
}, ...
})
Then, in my controller on a restricted method:
#cherrypy.expose
#cherrypy.tools.authenticate()
def home(self, **kwargs):
...
Most likely sessions aren't enabled. There's an example config file on the session wiki page, or have a look at tutorial #7.