I am going through a short Python tutorial, but I can't get the last exercise to work.
This is the source code of app.py
import web
urls = (
'/', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('templates/')
class Index(object):
def GET(self):
greeting = "Hello World"
return render.index(greeting = greeting)
if __name__ == "__main__":
app.run()
and this is the view, index.html
$def with (greeting)
<html>
<head>
<title>Gothons of Planet Percal #25</title>
</head>
<body>
$if greeting:
I just wanted to say <em style="color: green; font-size: 2em;">
greeting</em>.
$else:
<em>Hello</em>, world!
</body>
</html>
The file app.py is under this directory: C:\Users\Lucas\Desktop\Learn Python The Hard Way\ex50\gothonweb\bin
and index.html is at: C:\Users\Lucas\Desktop\Learn Python The Hard Way\ex50\gothonweb\templates
So, when I want to run the sample code, I type this in the command prompt:
C:\Python26\python.exe "C:\Users\Lucas\Desktop\Learn Python The Hard Way\ex50\gothonweb\bin\app.py"
After that, "http://0.0.0:8080" is displayed on the console, so I go to http://localhost:8080/ in my browser
but I get back a long traceback starting with
<type 'exceptions.AttributeError'> at /
No template named index
Python C:\Python26\lib\site-packages\web\template.py in _load_template, line 992
Web GET http://localhost:8080/
What is going on and how do I fix it?
Thanks in advance!
I had this problem as well but running on OSX. Ultimately Zed Shaw saw my pleas for help and saw the mistake I was making.
I was running
~/projects/gothonweb/bin $ python app.py
Zed reminded me that I needed to be running this:
~/projects/gothonweb $ python bin/app.py
to allow the templates folder to be found. After I did that it worked like a charm.
in windows ,the folder'name must write like this "c:\" not "c/",and you must use full path.
so the right code is render = web.template.render('d:\\documents\\python\\templates\\')
(app.py is in d:\documents\python)
You have a few typos, you need to refer to your view as Index when you use render (needs to be the same as the class name for your route):
return render.Index(greeting = greeting)
And your urls tuple needs a trailing comma:
urls = (
'/', 'Index',
)
Also make sure your template is named Index.html. Although, looking at the web.py tutorial, it looks like by convention you'd use lowercase for your route class.
Well, I suffered from the same problem, and I must say the error message is right, which indicates "you" cannot find the file, simply because you are not in the right path. So #davidheller #shellfly are right.
I use PyCharm as IDE to write python, so here is my solution:
Since I run the app.py, which is under the bin directory, thus render = web.template.render('../templates/')
which .. goes up and then found the file.
To conclude, we must be sure about the current path(even in windows), and both relative path or absolute path can be used in Windows environment, as shown below:
Absolute path.
Absolute path. Since Windows accepts both "/" and "\", we can write
render = web.template.render('C:/Users/Lucas/Desktop/Learn Python The Hard Way/ex50/gothonweb/templates/')
or
render = web.template.render('C:\\Users\\Lucas\\Desktop\\Learn Python The Hard Way\\ex50\\gothonweb\\templates\\')
Note, python interpreter interprets "\\" as "\"
Relative path.
render = web.template.render('../templates/')
You may need to compile the template like so
python web/template.py --compile templates
anyone using web.py with the Google app engine you will need to.
I am doing the same exercise and I simply go on cmd , cd to my lpthw directory which contains the folders of the project skeleton inside and do:
> python bin/app.py
I think you have to put all your files from the project skeleton in one folder and run your app from there. Hope this helps. :)
Related
When using:
#route('/<filename>')
def server_static(filename):
return static_file(filename, root='.')
it allows to serve the request www.example.com/helloworld with the static HTML file /myapp/helloworld.
How to make www.example.com/anything be served by the static HTML file /myapp/html/anything.html, without having to hardcode each static filename anything in the Python code?
Note: the tricky part is that the request is /anything (and not /anything.html), and the static file is /myapp/html/anything.html (there are 20 or more such files)
If it's always .html you could consider simply doing filename += '.html'.
If your needs are more complex, you could write code that examines the directory to match various extensions. For example, if you wanted to match .html files, something like this would work and would be adjustable to work with various/multiple extensions or other conditions.
def is_html(filename):
return filename.lower().endswith('.html')
#route('/<filename>')
def server_static(filename):
root = '.'
all_filenames = os.listdir(root)
html_files = filter(is_html, all_filenames)
for fname in html_files:
if fname.startswith(filename):
return static_file(fname, root=root)
else:
return "No such file"
This can probably be abbreviated using fnmatch or something similar.
Although, you may want to simply consider simply having a webserver like Apache simply serve that path instead of using Flask. This would probably be a more secure option, too.
I've tried to create my own Pypi repository, respecting https://www.python.org/dev/peps/pep-0503/. My idea was to put it in a shared directory (I'm using Windows), say host1/my-pypi. I've generated the index.html needed:
(dir) host1\my-pypi
-> (dir) toto
(file) index.html
(file) toto-1.0.0.whl
-> (file) index.html
the index.html files look somehow normal (same as in the pep-503). I try, from another computer, say host2 that has access to this shared directory to install toto package using:
pip install --index-url file://host1/my-pipy toto
but it fails (when it tries to read the file with a OSError: [Errno 22] Invalid argument: '\\\\host1\\my-pypi\\').
First, has anyone tried (and solved) this before? (That's the easy solution :-) ).
Second, I've dug a little in the code of pip, and there are a couple of things that are unclear to me (if there's ever a pro in pip that can answer ;-) ).
index.py, method find_all_candidates: it automatically changes my url list from [file://host1/my-pypi/toto], so it seems that it never tries to read host1\my-pypi\index.html... weird?
index.py, method get_page: well point 1 is not blocking for me as it magically matches my architecture, but there's a weird condition:
# Tack index.html onto file:// URLs that point to directories
(scheme, netloc, path, params, query, fragment) = \
urllib_parse.urlparse(url)
if (scheme == 'file' and
os.path.isdir(urllib_request.url2pathname(path))):
# add trailing slash if not present so urljoin doesn't trim
# final segment
if not url.endswith('/'):
url += '/'
url = urllib_parse.urljoin(url, 'index.html')
logger.debug(' file: URL is directory, getting %s', url)
resp = session.get(
url,
headers={
"Accept": "text/html",
"Cache-Control": "max-age=600",
},
)
well, as expected, we have:
scheme = 'file'
netloc = 'host1'
path = '/my-pypi/'
but the check condition os.path.isdir(urllib_request.url2pathname(path))) is obviously false as we've discarded the network location. Hence index.html is not appended to the path (that would've been correct otherwise), and hence the error while trying to read a file that does not exist.
For a remote UNC file share, specify the file URL with four slashes:
pip install --index-url file:////host1/my-pypi toto
In this case, the parsed netloc is empty and the path still includes the server hostname in UNC format, so isdir works correctly and index.html will be appended as expected.
I have tried to get the autoprefixer filter to work with flask_assets by following the instructions in the Flask_Assets documentation, but it does not appear to apply the filter. Here is my code:
# construct flask app object
from flask import Flask, render_template_string
flask_args = { 'import_name': __name__ }
flask_app = Flask(**flask_args)
from flask_assets import Environment, Bundle
assets = Environment(flask_app)
assets.config['AUTOPREFIXER_BIN'] = 'postcss'
assets.config['AUTOPREFIXER_BROWSERS'] = [ '> 1%' ]
css_min = Bundle('../styles/mycss.css', filters='autoprefixer', output='styles/test.css')
assets.register('css_assets', css_min)
#flask_app.route('/')
def landing_page():
html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\
<head>{% assets "css_assets" %}\
<link rel="stylesheet" href="{{ ASSET_URL }}" type="text/css">\
{% endassets %}\
<title>Hello</title>\
</head>\
<h1>Hello World</h1>\
<p>Just a test of flask</p>'
return render_template_string(html), 200
if __name__ == '__main__':
flask_app.run(host='0.0.0.0', port=5000)
I have been able to apply the cssmin, pyscss, uglifyjs and jsmin filters successfully. I can also run autoprefixer on the command line to successfully compile a transformed output:
postcss --use autoprefixer --autoprefixer.browsers "> 1%" -o test.css mycss.css
However, when trying to run autoprefixer through flask_assets registration, the process neither throws an error nor does it seem to take the required time to compile. It does produce the output file but when I examine the resulting file, none of the prefixes have been applied.
UPDATE: This problem seems to occur whenever attempting to configure options for ANY filter. I have not been able to get uglifyjs to accept 'UGLIFYJS_EXTRA_ARGS' or for the pyscss filter to adopt a new style using 'PYSCSS_STYLE' either. I have tried to set these configuration as environmental variables using os.environ['AUTOPREFIXER_BIN'] as well as attempting to pass them through flask.config['AUTOPREFIXER_BIN']. But none of the configuration settings have been applied when the filter is run. It is also not clear to me where in the code itself the configuration options are constructed by either Bundle or Environment.
One SO post claims to have found a way to get a configuration setting to work, but the post does not show the entire workflow of how flask_assets needs to be setup to ingest these options.
Perhaps someone can help me understand what I am doing wrong?
Autoprefixer:
There is nothing wrong with your code1. You are just not using the correct filter for the latest version of Autoprefixer. If you look at the history of the releases in that link, since version 6.0.0, it started using postcss. Your code will work for versions older than 6.0.0.
Webassets has provided support for versions after 6.0.0 (inclusive), by providing the autoprefixer6 filter.
Therefore all you have to do is change the filter(s) while initializing your bundle, like so:
css_min = Bundle('../styles/mycss.css', filters='autoprefixer6', output='styles/test.css')
Other Filters' Configurations:
Don't use os.environ, that is not the way to set configuration variables for Flask and flask-extensions. The most common (and preferred) way to set configuration for extensions is by using the flask Config itself, and in large projects this is done using a separate config file. The extensions will pickup its configuration options from flask's config.
Depending on which extension you use, you can also set the config separately like you have done, but that is rarely used, from what I have seen so far.
Please check the Flask's Configuration related documentation for some good examples on how to setup configuration for your app "properly".
from flask import Flask, render_template_string
from flask_assets import Environment, Bundle
# construct flask app object
flask_args = {'import_name': __name__}
flask_app = Flask(**flask_args)
assets = Environment(flask_app)
# specify the bin path (optional), required only if not globally installed
assets.config['AUTOPREFIXER_BIN'] = 'path/to/postcss'
assets.config['AUTOPREFIXER_BROWSERS'] = ['> 1%', ]
# use the autoprefixer6 updated filter
css_min = Bundle('../styles/mycss.css', filters='autoprefixer6',
output='styles/test.css')
assets.register('css_assets', css_min)
#flask_app.route('/')
def landing_page():
html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\
<head>{% assets "css_assets" %}\
<link rel="stylesheet" href="{{ ASSET_URL }}" type="text/css">\
{% endassets %}\
<title>Hello</title>\
</head>\
<h1>Hello World</h1>\
<p>Just a test of flask</p>'
return render_template_string(html), 200
if __name__ == '__main__':
flask_app.run(host='0.0.0.0', port=5000)
Remember to clean out the previously generated files, if the source css/js has not changed, i.e remove the output files, and the .webassets-cache folder.
1Except for code style & formatting conventions!
I'm trying to create a website using GAE(Google App Engine) as the server and Having pages rendered using the GAE Django API. The CSS style I'd like to use is the 960 Grid System, specifically the adaptive version found here.
My page is being rendered with Django in GAE as usual:
class MainPage(webapp.RequestHandler):
def get(self):
featuredPic = "img/featuredPic.jpg"
values = {
'featuredPic' : featuredPic,
}
self.response.out.write(template.render('index.html', values))
application = webapp.WSGIApplication([('/', MainPage)], debug=True)
And my index.html file also includes the code neccassarry for an adaptive grid system:
<script src="/js/adapt.js"></script>
<script>
// Edit to suit your needs.
var ADAPT_CONFIG = {
// Where is your CSS?
path : '/css/',
// false = Only run once, when page first loads.
// true = Change on window resize and page tilt.
dynamic : true,
// First range entry is the minimum.
// Last range entry is the maximum.
// Separate ranges by "to" keyword.
range : [ '0px to 760px = mobile.min.css',
'760px to 980px = 720.min.css',
'980px to 1280px = 960.min.css',
'1280px to 1600px = 1200.min.css',
'1600px to 1940px = 1560.min.css',
'1940px to 2540px = 1920.min.css',
'2540px = 2520.min.css' ]
};
</script>
Also I am including the css,js,img, and other folders in the app.yaml, yet despite all this the resulting HTML does not follow the 960 Grid System classes I have set to the divs. Does GAE disable JS or am I making some other mistake?
Actually, I am not that good at GAE, but I can help you, i guess.
I've also made a page on GAE and that has also template html file which uses the .js and .css files
At the template html file, I've written the script tag like the below.
<script type="application/x-javascript" src="iui/iui.js"></script>
and i put the .js file at the below path.
<app_name>\iui\iui.js
<app_name> has the models.py, urls.py, views.py, etc.
In addition, I've added the following statements on my app.yaml, "muchart" is <app_name>
app.yaml
...
handlers:
- url: /muchart/js
static_dir: muchart/js
- url: /muchart/iui
static_dir: muchart/iui
This doesn't exactly answer my question but I instead switched to the successor of 960.gs, Unsemantic, available here. It works really well with my project, as it was pretty much what I was looking for in the adaptive version of 960.gs. Also I had no issues setting it up.
I'm trying to use the pyfacebook functions (https://github.com/sciyoshi/pyfacebook/) in a Google app engine project. I've followed the advice on the Facebook developer forum (http://forum.developers.facebook.net/viewtopic.php?pid=164613) and added the additional functions to the __init__.py file, copied that file to the root directory of my project and renamed it facebook.py. Having imported facebook.py I added the following to the get(self) method for the Python class for the page:
facebookapi = facebook.Facebook(API_KEY, SECRET)
if not facebookapi.check_connect_session(self.request):
path = os.path.join(os.path.dirname(__file__), 'templates/login.html')
self.response.out.write(template.render(path, {'apikey': API_KEY}))
return
user = facebookapi.users.getInfo(
[facebookapi.uid],
['uid', 'name', 'birthday', 'relationship_status'])[0]
template_values = {
'name': user['name'],
'birthday': user['birthday'],
'relationship_status': user['relationship_status'],
'uid': user['uid'],
'apikey': API_KEY
}
path = os.path.join(os.path.dirname(__file__), 'templates/index.html')
self.response.out.write(template.render(path, template_values))
When running it I get the following error:
File "\much\baw08u\Private\IDS\helloworld\helloworld.py", line 54, in get
if not facebookapi.check_connect_session(self.request):
AttributeError: 'Facebook' object has no attribute 'check_connect_session'
So it seems to be loading the facebook API fine, but not the new methods I've added. I copied and pasted the code from the developer forum at the bottom of the Facebook class definition, and made sure all the indentation was right but it still doesn't seem to be picking them up. Does anyone know what might be the problem?
Thanks
Ben
You believe the Facebook class has a certain method but Python is sure it hasn't. Why? Maybe you misspelled the method name, maybe you did not get the indentation right - hard to say without seeing the code.
You could try poking around to validate your assumptions:
import facebook
import logging
logging.warn('Facebook class: %r', dir(facebook.Facebook))
logging.warn('facebook module: %r', dir(facebook))
If you are sure you are operating on the correct file, the you should expect to see check_connect_session as a method of Facebook. If you didn't add enough indentation then you expect to see check_connect_method as a function defined in the facebook module. Too much indentation would make check_connect_method a sub function of which ever method precedes it and it won't show up in the above logging. Pay close attention to indentation.
However, a better way to add some custom methods might be:
import facebook
class Facebook(facebook.Facebook):
def check_connect_session(request):
pass
facebookapi = Facebook(API_KEY, SECRET)
if not facebookapi.check_connect_session(...):
...
Now when Facebook update their code you simply copy the new file into place - no need to merge your customisations.