Merged revisions 66141,66145,66150,66180,66211,66217,66219,66226,66231,66244,66246,66249-66250,66264,66268,66272,66294,66306 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r66141 | gregory.p.smith | 2008-09-02 00:29:51 -0500 (Tue, 02 Sep 2008) | 3 lines Issue #3678: Correctly pass LDFLAGS and LDLAST to the linker on shared library targets in the Makefile. ........ r66145 | marc-andre.lemburg | 2008-09-02 05:32:34 -0500 (Tue, 02 Sep 2008) | 5 lines Add quotes around the file name to avoid issues with spaces. Closes #3719. ........ r66150 | marc-andre.lemburg | 2008-09-02 07:11:19 -0500 (Tue, 02 Sep 2008) | 3 lines Add news item for #3719. ........ r66180 | vinay.sajip | 2008-09-03 04:20:05 -0500 (Wed, 03 Sep 2008) | 1 line Issue #3726: Allowed spaces in separators in logging configuration files. ........ r66211 | vinay.sajip | 2008-09-04 02:31:21 -0500 (Thu, 04 Sep 2008) | 1 line Issue #3772: Fixed regression problem in StreamHandler.emit(). ........ r66217 | andrew.kuchling | 2008-09-04 08:26:24 -0500 (Thu, 04 Sep 2008) | 1 line #3671: various corrections and markup fixes noted by Kent Johnson ........ r66219 | hirokazu.yamamoto | 2008-09-04 09:25:30 -0500 (Thu, 04 Sep 2008) | 1 line Added NEWS ........ r66226 | benjamin.peterson | 2008-09-04 18:31:27 -0500 (Thu, 04 Sep 2008) | 1 line flesh out the documentation on using 2to3 ........ r66231 | andrew.kuchling | 2008-09-05 10:15:56 -0500 (Fri, 05 Sep 2008) | 1 line #3671: Typo fix ........ r66244 | jesse.noller | 2008-09-05 20:20:11 -0500 (Fri, 05 Sep 2008) | 2 lines Fix typo in multiprocessing doc, cancel_join_thread was missing _thread ........ r66246 | benjamin.peterson | 2008-09-05 22:00:00 -0500 (Fri, 05 Sep 2008) | 1 line actually tell the name of the flag to use ........ r66249 | andrew.kuchling | 2008-09-06 07:50:05 -0500 (Sat, 06 Sep 2008) | 1 line Various corrections ........ r66250 | andrew.kuchling | 2008-09-06 08:04:02 -0500 (Sat, 06 Sep 2008) | 1 line #3040: include 'dest' argument in example; trim some trailing whitespace ........ r66264 | benjamin.peterson | 2008-09-06 14:42:39 -0500 (Sat, 06 Sep 2008) | 1 line docs are pretty good about new-style classes these days ........ r66268 | andrew.kuchling | 2008-09-06 15:28:01 -0500 (Sat, 06 Sep 2008) | 1 line #3669 from Robert Lehmann: simplify use of iterator in example ........ r66272 | andrew.kuchling | 2008-09-06 16:26:02 -0500 (Sat, 06 Sep 2008) | 1 line #1317: describe the does_esmtp, ehlo_resp, esmtp_features, and helo_resp attributes ........ r66294 | georg.brandl | 2008-09-07 12:00:17 -0500 (Sun, 07 Sep 2008) | 2 lines Add a new howto about Python and the web, by Marek Kubica. ........ r66306 | mark.summerfield | 2008-09-08 09:45:37 -0500 (Mon, 08 Sep 2008) | 3 lines Added xrefs to each other. ........
This commit is contained in:
parent
e5b4ca6c99
commit
ae5360b31e
|
@ -21,4 +21,5 @@ Currently, the HOWTOs are:
|
|||
sockets.rst
|
||||
unicode.rst
|
||||
urllib2.rst
|
||||
webservers.rst
|
||||
|
||||
|
|
|
@ -0,0 +1,697 @@
|
|||
*******************************
|
||||
HOWTO Use Python in the web
|
||||
*******************************
|
||||
|
||||
:Author: Marek Kubica
|
||||
|
||||
.. topic:: Abstract
|
||||
|
||||
This document shows how Python fits into the web. It presents some ways on
|
||||
how to integrate Python with the web server and general practices useful for
|
||||
developing web sites.
|
||||
|
||||
|
||||
Programming for the Web has become a hot topic since the raise of the "Web 2.0",
|
||||
which focuses on user-generated content on web sites. It has always been
|
||||
possible to use Python for creating web sites, but it was a rather tedious task.
|
||||
Therefore, many so-called "frameworks" and helper tools were created to help
|
||||
developers creating sites faster and these sites being more robust. This HOWTO
|
||||
describes some of the methods used to combine Python with a web server to create
|
||||
dynamic content. It is not meant as a general introduction as this topic is far
|
||||
too broad to be covered in one single document. However, a short overview of
|
||||
the most popular libraries is provided.
|
||||
|
||||
.. seealso::
|
||||
|
||||
While this HOWTO tries to give an overview over Python in the Web, it cannot
|
||||
always be as up to date as desired. Web development in Python is moving
|
||||
forward rapidly, so the wiki page on `Web Programming
|
||||
<http://wiki.python.org/moin/WebProgramming>`_ might be more in sync with
|
||||
recent development.
|
||||
|
||||
|
||||
The low-level view
|
||||
==================
|
||||
|
||||
.. .. image:: http.png
|
||||
|
||||
When a user enters a web site, his browser makes a connection to the site's
|
||||
webserver (this is called the *request*). The server looks up the file in the
|
||||
file system and sends it back to the user's browser, which displays it (this is
|
||||
the *response*). This is roughly how the unterlying protocol, HTTP works.
|
||||
|
||||
Now, dynamic web sites are not files in the file system, but rather programs
|
||||
which are run by the web server when a request comes in. They can do all sorts
|
||||
of useful things, like display the postings of a bulletin board, show your
|
||||
mails, configurate software or just display the current time. These programs
|
||||
can be written in about any programming language the server supports, so it is
|
||||
easy to use Python for creating dynamic web sites.
|
||||
|
||||
As most of HTTP servers are written in C or C++, they cannot execute Python code
|
||||
in a simple way -- a bridge is needed between the server and the program. These
|
||||
bridges or rather interfaces define how programs interact with the server. In
|
||||
the past there have been numerous attempts to create the best possible
|
||||
interface, but there are only a few worth mentioning.
|
||||
|
||||
Not every web server supports every interface. Many web servers do support only
|
||||
old, now-obsolete interfaces. But they can often be extended using some
|
||||
third-party modules to support new interfaces.
|
||||
|
||||
|
||||
Common Gateway Interface
|
||||
------------------------
|
||||
|
||||
This interface is the oldest one, supported by nearly every web server out of
|
||||
the box. Programs using CGI to communicate with their web server need to be
|
||||
started by the server for every request. So, every request starts a new Python
|
||||
interpreter -- which takes some time to start up -- thus making the whole
|
||||
interface only usable for low load situations.
|
||||
|
||||
The upside of CGI is that it is simple -- writing a program which uses CGI is a
|
||||
matter of about three lines of code. But this simplicity comes at a price: it
|
||||
does very few things to help the developer.
|
||||
|
||||
Writing CGI programs, while still possible, is not recommended anymore. With
|
||||
WSGI (more on that later) it is possible to write programs that emulate CGI, so
|
||||
they can be run as CGI if no better option is available.
|
||||
|
||||
.. seealso::
|
||||
|
||||
The Python standard library includes some modules that are helpful for
|
||||
creating plain CGI programs:
|
||||
|
||||
* :mod:`cgi` -- Handling of user input in CGI scripts
|
||||
* :mod:`cgitb` -- Displays nice tracebacks when errors happen in of CGI
|
||||
applications, instead of presenting a "500 Internal Server Error" message
|
||||
|
||||
The Python wiki features a page on `CGI scripts
|
||||
<http://wiki.python.org/moin/CgiScripts>`_ with some additional information
|
||||
about CGI in Python.
|
||||
|
||||
|
||||
Simple script for testing CGI
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To test whether your web server works with CGI, you can use this short and
|
||||
simple CGI program::
|
||||
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
# enable debugging
|
||||
import cgitb; cgitb.enable()
|
||||
|
||||
print "Content-Type: text/plain;charset=utf-8"
|
||||
print
|
||||
|
||||
print "Hello World!"
|
||||
|
||||
You need to write this code into a file with a ``.py`` or ``.cgi`` extension,
|
||||
this depends on your web server configuration. Depending on your web server
|
||||
configuration, this file may also need to be in a ``cgi-bin`` folder, for
|
||||
security reasons.
|
||||
|
||||
You might wonder what the ``cgitb`` line is about. This line makes it possible
|
||||
to display a nice traceback instead of just crashing and displaying an "Internal
|
||||
Server Error" in the user's browser. This is useful for debugging, but it might
|
||||
risk exposing some confident data to the user. Don't use it when the script is
|
||||
ready for production use. Still, you should *always* catch exceptions, and
|
||||
display proper error pages -- end-users don't like to see nondescript "Internal
|
||||
Server Errors" in their browsers.
|
||||
|
||||
|
||||
Setting up CGI on your own server
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you don't have your own web server, this does not apply to you. You can
|
||||
check whether if works as-is and if not you need to talk to the administrator of
|
||||
your web server anyway. If it is a big hoster, you can try filing a ticket
|
||||
asking for Python support.
|
||||
|
||||
If you're your own administrator or want to install it for testing purposes on
|
||||
your own computers, you have to configure it by yourself. There is no one and
|
||||
single way on how to configure CGI, as there are many web servers with different
|
||||
configuration options. The currently most widely used free web server is
|
||||
`Apache HTTPd <http://httpd.apache.org/>`_, Apache for short -- this is the one
|
||||
that most people use, it can be easily installed on nearly every system using
|
||||
the systems' package management. But `lighttpd <http://www.lighttpd.net>`_ has
|
||||
been gaining attention since some time and is said to have a better performance.
|
||||
On many systems this server can also be installed using the package management,
|
||||
so manually compiling the web server is never needed.
|
||||
|
||||
* On Apache you can take a look into the `Dynamic Content with CGI
|
||||
<http://httpd.apache.org/docs/2.2/howto/cgi.html>`_ tutorial, where everything
|
||||
is described. Most of the time it is enough just to set ``+ExecCGI``. The
|
||||
tutorial also describes the most common gotchas that might arise.
|
||||
* On lighttpd you need to use the `CGI module
|
||||
<http://trac.lighttpd.net/trac/wiki/Docs%3AModCGI>`_ which can be configured
|
||||
in a straightforward way. It boils down to setting ``cgi.assign`` properly.
|
||||
|
||||
|
||||
Common problems with CGI scripts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Trying to use CGI sometimes leads to small annoyances that one might experience
|
||||
while trying to get these scripts to run. Sometimes it happens that a seemingly
|
||||
correct script does not work as expected, which is caused by some small hidden
|
||||
reason that's difficult to spot.
|
||||
|
||||
Some of these reasons are:
|
||||
|
||||
* The Python script is not marked executable. When CGI scripts are not
|
||||
executable most of the web servers will let the user download it, instead of
|
||||
running it and sending the output to the user. For CGI scripts to run
|
||||
properly the ``+x`` bit needs to be set. Using ``chmod a+x your_script.py``
|
||||
might already solve the problem.
|
||||
* The line endings must be of Unix-type. This is important because the web
|
||||
server checks the first line of the script (called shebang) and tries to run
|
||||
the program specified there. It gets easily confused by Windows line endings
|
||||
(Carriage Return & Line Feed, also called CRLF), so you have to convert the
|
||||
file to Unix line endings (only Line Feed, LF). This can be done
|
||||
automatically by uploading the file via FTP in text mode instead of binary
|
||||
mode, but the preferred way is just telling your editor to save the files with
|
||||
Unix line endings. Most proper editors support this.
|
||||
* Your web server must be able to read the file, you need to make sure the
|
||||
permissions are fine. Often the server runs as user and group ``www-data``,
|
||||
so it might be worth a try to change the file ownership or making the file
|
||||
world readable by using ``chmod a+r your_script.py``.
|
||||
* The webserver must be able to know that the file you're trying to access is a
|
||||
CGI script. Check the configuration of your web server, maybe there is some
|
||||
mistake.
|
||||
* The path to the interpreter in the shebang (``#!/usr/bin/env python``) must be
|
||||
currect. This line calls ``/usr/bin/env`` to find Python, but it'll fail if
|
||||
there is no ``/usr/bin/env``. If you know where your Python is installed, you
|
||||
can also use that path. The commands ``whereis python`` and ``type -p
|
||||
python`` might also help to find where it is installed. Once this is known,
|
||||
the shebang line can be changed accordingly: ``#!/usr/bin/python``.
|
||||
* The file must not contain a BOM (Byte Order Mark). The BOM is meant for
|
||||
determining the byte order of UTF-16 encodings, but some editors write this
|
||||
also into UTF-8 files. The BOM interferes with the shebang line, so be sure
|
||||
to tell your editor not to write the BOM.
|
||||
* :ref:`mod-python` might be making problems. mod_python is able to handle CGI
|
||||
scripts by itself, but it can also be a source for problems. Be sure you
|
||||
disable it.
|
||||
|
||||
|
||||
.. _mod-python:
|
||||
|
||||
mod_python
|
||||
----------
|
||||
|
||||
People coming from PHP often find it hard to grasp how to use Python in the web.
|
||||
Their first thought is mostly `mod_python <http://www.modpython.org/>`_ because
|
||||
they think that this is the equivalent to ``mod_php``. Actually it is not
|
||||
really. It does embed the interpreter into the Apache process, thus speeding up
|
||||
requests by not having to start a Python interpreter every request. On the
|
||||
other hand, it is by far not "Python intermixed with HTML" as PHP often does.
|
||||
The Python equivalent of that is a template engine. mod_python itself is much
|
||||
more powerful and gives more access to Apache internals. It can emulate CGI, it
|
||||
can work an a "Python Server Pages" mode similar to JSP which is "HTML
|
||||
intermangled with Python" and it has a "Publisher" which destignates one file to
|
||||
accept all requests and decide on what to do then.
|
||||
|
||||
But mod_python has some problems. Unlike the PHP interpreter the Python
|
||||
interpreter uses caching when executing files, so when changing a file the whole
|
||||
web server needs to be re-started to update. Another problem ist the basic
|
||||
concept -- Apache starts some child processes to handle the requests and
|
||||
unfortunately every child process needs to load the whole Python interpreter
|
||||
even if it does not use it. This makes the whole web server slower. Another
|
||||
problem is that as mod_python is linked against a specific version of
|
||||
``libpython``, it is not possible to switch from an older version to a newer
|
||||
(e.g. 2.4 to 2.5) without recompiling mod_python. mod_python is also bound to
|
||||
the Apache web server, so programs written for mod_python cannot easily run on
|
||||
other web servers.
|
||||
|
||||
These are the reasons why mod_python should be avoided when writing new
|
||||
programs. In some circumstances it might be still a good idea to use mod_python
|
||||
for deployment, but WSGI makes it possible to run WSGI programs under mod_python
|
||||
as well.
|
||||
|
||||
|
||||
FastCGI and SCGI
|
||||
----------------
|
||||
|
||||
FastCGI and SCGI try to solve the performance problem of CGI in another way.
|
||||
Instead of embedding the interpreter into the web server, they create
|
||||
long-running processes which run in the background. There still is some module
|
||||
in the web server which makes it possible for the web server to "speak" with the
|
||||
background process. As the background process is independent from the server,
|
||||
it can be written in any language of course also in Python. The language just
|
||||
needs to have a library which handles the communication with the web server.
|
||||
|
||||
The difference between FastCGI and SCGI is very small, as SCGI is essentially
|
||||
just a "simpler FastCGI". But as the web server support for SCGI is limited
|
||||
most people use FastCGI instead, which works the same way. Almost everything
|
||||
that applies to SCGI also applies to FastCGI as well, so we'll only write about
|
||||
the latter.
|
||||
|
||||
These days, FastCGI is never used directly. Just like ``mod_python`` it is only
|
||||
used for the deployment of WSGI applications.
|
||||
|
||||
.. seealso::
|
||||
|
||||
* `FastCGI, SCGI, and Apache: Background and Future
|
||||
<http://www.vmunix.com/mark/blog/archives/2006/01/02/fastcgi-scgi-and-apache-background-and-future/>`_
|
||||
is a discussion on why the concept of FastCGI and SCGI is better that that
|
||||
of mod_python.
|
||||
|
||||
|
||||
Setting up FastCGI
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Depending on the web server you need to have a special module.
|
||||
|
||||
* Apache has both `mod_fastcgi <http://www.fastcgi.com/>`_ and `mod_fcgid
|
||||
<http://fastcgi.coremail.cn/>`_. ``mod_fastcgi`` is the original one, but it
|
||||
has some licensing issues that's why it is sometimes considered non-free.
|
||||
``mod_fcgid`` is a smaller, compatible alternative. One of these modules needs
|
||||
to be loaded by Apache.
|
||||
* lighttpd ships its own `FastCGI module
|
||||
<http://trac.lighttpd.net/trac/wiki/Docs%3AModFastCGI>`_ as well as an `SCGI
|
||||
module <http://trac.lighttpd.net/trac/wiki/Docs%3AModSCGI>`_.
|
||||
* nginx also supports `FastCGI
|
||||
<http://wiki.codemongers.com/NginxSimplePythonFCGI>`_.
|
||||
|
||||
Once you have installed and configured the module, you can test it with the
|
||||
following WSGI-application::
|
||||
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from cgi import escape
|
||||
import sys, os
|
||||
from flup.server.fcgi import WSGIServer
|
||||
|
||||
def app(environ, start_response):
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
|
||||
yield '<h1>FastCGI Environment</h1>'
|
||||
yield '<table>'
|
||||
for k, v in sorted(environ.items()):
|
||||
yield '<tr><th>%s</th><td>%s</td></tr>' % (escape(k), escape(v))
|
||||
yield '</table>'
|
||||
|
||||
WSGIServer(app).run()
|
||||
|
||||
This is a simple WSGI application, but you need to install `flup
|
||||
<http://pypi.python.org/pypi/flup/1.0>`_ first, as flup handles the low level
|
||||
FastCGI access.
|
||||
|
||||
.. seealso::
|
||||
|
||||
There is some documentation on `setting up Django with FastCGI
|
||||
<http://www.djangoproject.com/documentation/fastcgi/>`_, most of which can be
|
||||
reused for other WSGI-compliant frameworks and libraries. Only the
|
||||
``manage.py`` part has to be changed, the example used here can be used
|
||||
instead. Django does more or less the exact same thing.
|
||||
|
||||
|
||||
mod_wsgi
|
||||
--------
|
||||
|
||||
`mod_wsgi <http://www.modwsgi.org/>`_ is an attempt to get rid of the low level
|
||||
gateways. As FastCGI, SCGI, mod_python are mostly used to deploy WSGI
|
||||
applications anyway, mod_wsgi was started to directly embed WSGI aplications
|
||||
into the Apache web server. The benefit from this approach is that WSGI
|
||||
applications can be deployed much easier as is is specially designed to host
|
||||
WSGI applications -- unlike the other low level methods which have glue code to
|
||||
host WSGI applications (like flup which was mentioned before). The downside is
|
||||
that mod_wsgi is limited to the Apache web server, other servers would need
|
||||
their own implementations of mod_wsgi.
|
||||
|
||||
It supports two modes: the embedded mode in which it integrates with the Apache
|
||||
process and the daemon mode which is more FastCGI-like. Contrary to FastCGI,
|
||||
mod_wsgi handles the worker-processes by itself which makes administration
|
||||
easier.
|
||||
|
||||
|
||||
.. _WSGI:
|
||||
|
||||
Step back: WSGI
|
||||
===============
|
||||
|
||||
WSGI was already mentioned several times so it has to be something important.
|
||||
In fact it really is, so now it's time to explain.
|
||||
|
||||
The *Web Server Gateway Interface*, :pep:`333` or WSGI for short is currently
|
||||
the best possible way to Python web programming. While it is great for
|
||||
programmers writing frameworks, the normal person does not need to get in direct
|
||||
contact with it. But when choosing a framework for web development it is a good
|
||||
idea to take one which supports WSGI.
|
||||
|
||||
The big profit from WSGI is the unification. When your program is compatible
|
||||
with WSGI -- that means that your framework has support for WSGI, your program
|
||||
can be deployed on every web server interface for which there are WSGI wrappers.
|
||||
So you do not need to care about whether the user uses mod_python or FastCGI --
|
||||
with WSGI it just works on any gateway interface. The Python standard library
|
||||
contains its own WSGI server :mod:`wsgiref`, which is a small web server that
|
||||
can be used for testing.
|
||||
|
||||
A really great WSGI feature are the middlewares. Middlewares are layers around
|
||||
your program which can add various functionality to it. There is a `number of
|
||||
middlewares <http://wsgi.org/wsgi/Middleware_and_Utilities>`_ already available.
|
||||
For example, instead of writing your own session management (to identify a user
|
||||
in subsequent requests, as HTTP does not maintain state, so it does now know
|
||||
that the requests belong to the same user) you can just take one middleware,
|
||||
plug it in and you can rely an already existing functionality. The same thing
|
||||
is compression -- say you want to compress your HTML using gzip, to save your
|
||||
server's bandwidth. So you only need to plug-in a middleware and you're done.
|
||||
Authentication is also a problem easily solved using a middleware.
|
||||
|
||||
So, generally -- although WSGI may seem complex, the initial phase of learning
|
||||
can be very rewarding as WSGI does already have solutions to many problems that
|
||||
might arise while writing web sites.
|
||||
|
||||
|
||||
WSGI Servers
|
||||
------------
|
||||
|
||||
The code that is used to connect to various low level gateways like CGI or
|
||||
mod_python is called *WSGI server*. One of these servers is ``flup`` which was
|
||||
already mentioned and supports FastCGI, SCGI as well as `AJP
|
||||
<http://en.wikipedia.org/wiki/Apache_JServ_Protocol>`_. Some of these servers
|
||||
are written in Python as ``flup`` is, but there also exist others which are
|
||||
written in C and can be used as drop-in replacements.
|
||||
|
||||
There are quite a lot of servers already available, so a Python web application
|
||||
can be deployed nearly everywhere. This is one big advantage that Python has
|
||||
compared with other web techniques.
|
||||
|
||||
.. seealso::
|
||||
|
||||
A good overview of all WSGI-related code can be found in the `WSGI wiki
|
||||
<http://wsgi.org/wsgi>`_, which contains an extensive list of `WSGI servers
|
||||
<http://wsgi.org/wsgi/Servers>`_, which can be used by *every* application
|
||||
supporting WSGI.
|
||||
|
||||
You might be interested in some WSGI-supporting modules already contained in
|
||||
the standard library, namely:
|
||||
|
||||
* :mod:`wsgiref` -- some tiny utilities and servers for WSGI
|
||||
|
||||
|
||||
Case study: MoinMoin
|
||||
--------------------
|
||||
|
||||
What does WSGI give the web application developer? Let's take a look on one
|
||||
long existing web application written in Python without using WSGI.
|
||||
|
||||
One of the most widely used wiki software is `MoinMoin <http://moinmo.in/>`_.
|
||||
It was created in 2000, so it predates WSGI by about three years. While it now
|
||||
includes support for WSGI, older versions needed separate code to run on CGI,
|
||||
mod_python, FastCGI and standalone. Now, this all is possible by using WSGI and
|
||||
the already-written gateways. For running with on FastCGI ``flup`` can be used,
|
||||
for running a standalone server :mod:`wsgiref` is the way to go.
|
||||
|
||||
|
||||
Model-view-controller
|
||||
=====================
|
||||
|
||||
The term *MVC* is often heard in statements like "framework *foo* supports MVC".
|
||||
While MVC is not really something technical but rather organisational, many web
|
||||
frameworks use this model to help the developer to bring structure into his
|
||||
program. Bigger web applications can have lots of code so it is a good idea to
|
||||
have structure in the program right from the beginnings. That way, even users
|
||||
of other frameworks (or even languages, as MVC is nothing Python-specific) can
|
||||
understand the existing code easier, as they are already familiar with the
|
||||
structure.
|
||||
|
||||
MVC stands for three components:
|
||||
|
||||
* The *model*. This is the data that is meant to modify. In Python frameworks
|
||||
this component is often represented by the classes used by the
|
||||
object-relational mapper. So, all declarations go here.
|
||||
* The *view*. This component's job is to display the data of the model to the
|
||||
user. Typically this component is represented by the templates.
|
||||
* The *controller*. This is the layer between the user and the model. The
|
||||
controller reacts on user actions (like opening some specific URL) and tells
|
||||
the model to modify the data if neccessary.
|
||||
|
||||
While one might think that MVC is a complex design pattern, in fact it is not.
|
||||
It is used in Python because it has turned out to be useful for creating clean,
|
||||
maintainable web sites.
|
||||
|
||||
.. note::
|
||||
|
||||
While not all Python frameworks explicitly support MVC, it is often trivial
|
||||
to create a web site which uses the MVC pattern by seperating the data logic
|
||||
(the model) from the user interaction logic (the controller) and the
|
||||
templates (the view). That's why it is important not to write unneccessary
|
||||
Python code in the templates -- it is against MVC and creates more chaos.
|
||||
|
||||
.. seealso::
|
||||
|
||||
The english Wikipedia has an article about the `Model-View-Controller pattern
|
||||
<http://en.wikipedia.org/wiki/Model-view-controller>`_, which includes a long
|
||||
list of web frameworks for different programming languages.
|
||||
|
||||
|
||||
Ingredients for web sites
|
||||
=========================
|
||||
|
||||
Web sites are complex constructs, so tools were created to help the web site
|
||||
developer to make his work maintainable. None of these tools are in any way
|
||||
Python specific, they also exist for other programming languages as well. Of
|
||||
course, developers are not forced to use these tools and often there is no
|
||||
"best" tool, but it is worth informing yourself before choosing something
|
||||
because of the big number of helpers that the developer can use.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
People have written far more components that can be combined than these
|
||||
presented here. The Python wiki has a page about these components, called
|
||||
`Web Components <http://wiki.python.org/moin/WebComponents>`_.
|
||||
|
||||
|
||||
Templates
|
||||
---------
|
||||
|
||||
Mixing of HTML and Python code is possible with some libraries. While
|
||||
convenient at first, it leads to horribly unmaintainable code. That's why
|
||||
templates exist. Templates are, in the simplest case, just HTML files with
|
||||
placeholders. The HTML is sent to the user's browser after filling out the
|
||||
placeholders.
|
||||
|
||||
Python already includes such simple templates::
|
||||
|
||||
# a simple template
|
||||
template = "<html><body><h1>Hello %s!</h1></body></html>"
|
||||
print template % "Reader"
|
||||
|
||||
The Python standard library also includes some more advanced templates usable
|
||||
through :class:`string.Template`, but in HTML templates it is needed to use
|
||||
conditional and looping contructs like Python's *for* and *if*. So, some
|
||||
*template engine* is needed.
|
||||
|
||||
Now, Python has a lot of template engines which can be used with or without a
|
||||
`framework`_. Some of these are using a plain-text programming language which
|
||||
is very easy to learn as it is quite limited while others use XML so the
|
||||
template output is always guaranteed to be valid XML. Some `frameworks`_ ship
|
||||
their own template engine or recommend one particular. If one is not yet sure,
|
||||
using these is a good idea.
|
||||
|
||||
.. note::
|
||||
|
||||
While Python has quite a lot of different template engines it usually does
|
||||
not make sense to use a homebrewed template system. The time needed to
|
||||
evaluate all templating systems is not really worth it, better invest the
|
||||
time in looking through the most popular ones. Some frameworks have their
|
||||
own template engine or have a recommentation for one. It's wise to use
|
||||
these.
|
||||
|
||||
Popular template engines include:
|
||||
|
||||
* Mako
|
||||
* Genshi
|
||||
* Jinja
|
||||
|
||||
.. seealso::
|
||||
|
||||
Lots of different template engines divide the attention between themselves
|
||||
because it's easy to create them in Python. The page `Templating
|
||||
<http://wiki.python.org/moin/Templating>`_ in the wiki lists a big,
|
||||
ever-growing number of these.
|
||||
|
||||
|
||||
Data persistence
|
||||
----------------
|
||||
|
||||
*Data persistence*, while sounding very complicated is just about storing data.
|
||||
This data might be the text of blog entries, the postings of a bulletin board or
|
||||
the text of a wiki page. As always, there are different ways to store
|
||||
informations on a web server.
|
||||
|
||||
Often relational database engines like `MySQL <http://www.mysql.com/>`_ or
|
||||
`PostgreSQL <http://http://www.postgresql.org/>`_ are used due to their good
|
||||
performance handling very large databases consisting of up to millions of
|
||||
entries. These are *queried* using a language called `SQL
|
||||
<http://en.wikipedia.org/wiki/SQL>`_. Python programmers in general do not like
|
||||
SQL too much, they prefer to work with objects. It is possible to save Python
|
||||
objects into a database using a technology called `ORM
|
||||
<http://en.wikipedia.org/wiki/Object-relational_mapping>`_. ORM translates all
|
||||
object-oriented access into SQL code under the hood, the user does not need to
|
||||
think about it. Most `frameworks`_ use ORMs and it works quite well.
|
||||
|
||||
A second possibility is using files that are saved on the hard disk (sometimes
|
||||
called flatfiles). This is very easy, but is not too fast. There is even a
|
||||
small database engine called `SQLite <http://www.sqlite.org/>`_ which is bundled
|
||||
with Python in the :mod:`sqlite` module and uses only one file. This database
|
||||
can be used to store objects via an ORM and has no other dependencies. For
|
||||
smaller sites SQLite is just enough. But it is not the only way in which data
|
||||
can be saved into the file systems. Sometimes normal, plain text files are
|
||||
enough.
|
||||
|
||||
The third and least used possibility are so-called object oriented databases.
|
||||
These databases store the *actual objects* instead of the relations that
|
||||
OR-mapping creates between rows in a database. This has the advantage that
|
||||
nearly all objects can be saven in a straightforward way, unlike in relational
|
||||
databases where some objects are very hard to represent with ORMs.
|
||||
|
||||
`Frameworks`_ often give the users hints on which method to choose, it is
|
||||
usually a good idea to stick to these unless there are some special requirements
|
||||
which require to use the one method and not the other.
|
||||
|
||||
.. seealso::
|
||||
|
||||
* `Persistence Tools <http://wiki.python.org/moin/PersistenceTools>`_ lists
|
||||
possibilities on how to save data in the file system, some of these modules
|
||||
are part of the standard library
|
||||
* `Database Programming <http://wiki.python.org/moin/DatabaseProgramming>`_
|
||||
helps on choosing a method on how to save the data
|
||||
* `SQLAlchemy <http://www.sqlalchemy.org/>`_, the most powerful OR-Mapper for
|
||||
Python and `Elixir <http://elixir.ematia.de/>`_ which makes it easier to
|
||||
use
|
||||
* `SQLObject <http://www.sqlobject.org/>`_, another popular OR-Mapper
|
||||
* `ZODB <https://launchpad.net/zodb>`_ and `Durus
|
||||
<http://www.mems-exchange.org/software/durus/>`_, two object oriented
|
||||
databases
|
||||
|
||||
|
||||
.. _framework:
|
||||
|
||||
Frameworks
|
||||
==========
|
||||
|
||||
As web sites can easily become quite large, there are so-called frameworks which
|
||||
were created to help the developer with making these sites. Although the most
|
||||
well-known framework is Ruby on Rails, Python does also have its own frameworks
|
||||
which are partly inspired by Rails or which were existing a long time before
|
||||
Rails.
|
||||
|
||||
Two possible approaches to web frameworks exist: the minimalistic approach and
|
||||
the all-inclusive approach (somtimes called *full-stack*). Frameworks which are
|
||||
all-inclusive give you everything you need to start working, like a template
|
||||
engine, some way to save and access data in databases and many features more.
|
||||
Most users are best off using these as they are widely used by lots of other
|
||||
users and well documented in form of books and tutorials. Other web frameworks
|
||||
go the minimalistic approach trying to be as flexible as possible leaving the
|
||||
user the freedom to choose what's best for him.
|
||||
|
||||
The majority of users is best off with all-inclusive framewors. They bring
|
||||
everything along so a user can just jump in and start to code. While they do
|
||||
have some limitations they can fullfill 80% of what one will ever want to
|
||||
perfectly. They consist of various components which are designed to work
|
||||
together as good as possible.
|
||||
|
||||
The multitude of web frameworks written in Python demonstrates that it is really
|
||||
easy to write one. One of the most well-known web applications written in
|
||||
Python is `Zope <http://www.zope.org/>`_ which can be regarded as some kind of
|
||||
big framework. But Zope was not the only framework, there were some others
|
||||
which are by now nearly forgotten. These do not need to be mentioned anymore,
|
||||
because most people that used them moved on to newer ones.
|
||||
|
||||
|
||||
Some notable frameworks
|
||||
-----------------------
|
||||
|
||||
There is an incredible number of frameworks, so there is no way to describe them
|
||||
all. It is not even neccessary, as most of these frameworks are nothing special
|
||||
and everything that can be done with these can also be done with one of the
|
||||
popular ones.
|
||||
|
||||
|
||||
Django
|
||||
^^^^^^
|
||||
|
||||
`Django <http://www.djangoproject.com/>`_ is a framework consisting of several
|
||||
tightly coupled elements which were written from scratch and work together very
|
||||
well. It includes an ORM which is quite powerful while being simple to use and
|
||||
has a great online administration interface which makes it possible to edit the
|
||||
data in the database with a browser. The template engine is text-based and is
|
||||
designed to be usable for page designers who cannot write Python. It supports
|
||||
so-called template inheritance and filters (which work like Unix pipes). Django
|
||||
has many handy features bundled, like creation of RSS feeds or generic views
|
||||
which make it possible to write web sites nearly without any Python code.
|
||||
|
||||
It has a big, international community which has created many sites using Django.
|
||||
There are also quite a lot of add-on projects which extend Django's normal
|
||||
functionality. This is partly due to Django's well written `online
|
||||
documentation <http://doc.djangoproject.com/>`_ and the `Django book
|
||||
<http://www.djangobook.com/>`_.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Although Django is an MVC-style framework, it calls the components
|
||||
differently, which is described in the `Django FAQ
|
||||
<http://www.djangoproject.com/documentation/faq/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names>`_.
|
||||
|
||||
|
||||
TurboGears
|
||||
^^^^^^^^^^
|
||||
|
||||
The other popular web framework in Python is `TurboGears
|
||||
<http://www.turbogears.org/>`_. It takes the approach of using already existing
|
||||
components and combining them with glue code to create a seamless experience.
|
||||
TurboGears gives the user more flexibility on which components to choose, the
|
||||
ORM can be switched between some easy to use but limited and complex but very
|
||||
powerful. Same goes for the template engine. One strong point about TurboGears
|
||||
is that the components that it consists of can be used easily in other projects
|
||||
without depending on TurboGears, for example the underlying web server CherryPy.
|
||||
|
||||
The documentation can be found in the `TurboGears wiki
|
||||
<http://docs.turbogears.org/>`_, where links to screencasts can be found.
|
||||
TurboGears has also an active user community which can respond to most related
|
||||
questions. There is also a `TurboGears book <http://turbogearsbook.com/>`_
|
||||
published, which is a good starting point.
|
||||
|
||||
The plan for the next major version of TurboGears, version 2.0 is to switch to a
|
||||
more flexible base provided by another very flexible web framework called
|
||||
`Pylons <http://pylonshq.com/>`_.
|
||||
|
||||
|
||||
Other notable frameworks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
These two are of course not the only frameworks that are available, there are
|
||||
also some less-popular frameworks worth mentioning.
|
||||
|
||||
One of these is the already mentioned Zope, which has been around for quite a
|
||||
long time. With Zope 2.x having been known as rather un-pythonic, the newer
|
||||
Zope 3.x tries to change that and therefore gets more acceptance from Python
|
||||
programmers. These efforts already showed results, there is a project which
|
||||
connects Zope with WSGI called `Repoze <http://repoze.org/>`_ and another
|
||||
project called `Grok <http://grok.zope.org/>`_ which makes it possible for
|
||||
"normal" Python programmers use the very mature Zope components.
|
||||
|
||||
Another framework that's already been mentioned is `Pylons`_. Pylons is much
|
||||
like TurboGears with ab even stronger emphasis on flexibility, which is bought
|
||||
at the cost of being more difficult to use. Nearly every component can be
|
||||
exchanged, which makes it neccessary to use the documentation of every single
|
||||
component, because there are so many Pylons combinations possible that can
|
||||
satisfy every requirement. Pylons builds upon `Paste
|
||||
<http://pythonpaste.org/>`_, an extensive set of tools which are handy for WSGI.
|
||||
|
||||
And that's still not everything. The most up-to-date information can always be
|
||||
found in the Python wiki.
|
||||
|
||||
.. seealso::
|
||||
|
||||
The Python wiki contains an extensive list of `web frameworks
|
||||
<http://wiki.python.org/moin/WebFrameworks>`_.
|
||||
|
||||
Most frameworks also have their own mailing lists and IRC channels, look out
|
||||
for these on the projects' websites. There is also a general "Python in the
|
||||
Web" IRC channel on freenode called `#python.web
|
||||
<http://wiki.python.org/moin/PoundPythonWeb>`_.
|
|
@ -7,15 +7,21 @@
|
|||
|
||||
2to3 is a Python program that reads Python 2.x source code and applies a series
|
||||
of *fixers* to transform it into valid Python 3.x code. The standard library
|
||||
contains a rich set of fixers that will handle almost all code. It is, however,
|
||||
possible to write your own fixers.
|
||||
contains a rich set of fixers that will handle almost all code. 2to3 supporting
|
||||
library :mod:`lib2to3` is, however, a flexible and generic library, so it is
|
||||
possible to write your own fixers for 2to3. :mod:`lib2to3` could also be
|
||||
adapted to custom applications in which Python code needs to be edited
|
||||
automatically.
|
||||
|
||||
|
||||
Using 2to3
|
||||
----------
|
||||
|
||||
2to3 can be run with a list of files to transform or a directory to recursively
|
||||
traverse looking for files with the ``.py`` extension.
|
||||
2to3 will usually be installed with the Python interpreter as a script. It is
|
||||
also located in the :file:`Tools/scripts` directory of the Python root.
|
||||
|
||||
2to3's basic arguments are a list of files or directories to transform. The
|
||||
directories are to recursively traversed for Python sources.
|
||||
|
||||
Here is a sample Python 2.x source file, :file:`example.py`::
|
||||
|
||||
|
@ -29,13 +35,14 @@ It can be converted to Python 3.x code via 2to3 on the command line::
|
|||
|
||||
$ 2to3 example.py
|
||||
|
||||
A diff against the original source file will be printed. 2to3 can also write
|
||||
the needed modifications right back to the source file. (A backup of the
|
||||
original file will also be made.) This is done with the :option:`-w` flag::
|
||||
A diff against the original source file is printed. 2to3 can also write the
|
||||
needed modifications right back to the source file. (Of course, a backup of the
|
||||
original is also be made.) Writing the changes back is enabled with the
|
||||
:option:`-w` flag::
|
||||
|
||||
$ 2to3 -w example.py
|
||||
|
||||
:file:`example.py` will now look like this::
|
||||
After transformation, :file:`example.py` looks like this::
|
||||
|
||||
def greet(name):
|
||||
print("Hello, {0}!".format(name))
|
||||
|
@ -43,10 +50,10 @@ original file will also be made.) This is done with the :option:`-w` flag::
|
|||
name = input()
|
||||
greet(name)
|
||||
|
||||
Comments and and exact indentation will be preserved throughout the translation
|
||||
Comments and and exact indentation are preserved throughout the translation
|
||||
process.
|
||||
|
||||
By default, 2to3 will run a set of predefined fixers. The :option:`-l` flag
|
||||
By default, 2to3 runs a set of predefined fixers. The :option:`-l` flag
|
||||
lists all avaible fixers. An explicit set of fixers to run can be given by use
|
||||
of the :option:`-f` flag. The following example runs only the ``imports`` and
|
||||
``has_key`` fixers::
|
||||
|
@ -54,16 +61,30 @@ of the :option:`-f` flag. The following example runs only the ``imports`` and
|
|||
$ 2to3 -f imports -f has_key example.py
|
||||
|
||||
Some fixers are *explicit*, meaning they aren't run be default and must be
|
||||
listed on the command line. Here, in addition to the default fixers, the
|
||||
``idioms`` fixer is run::
|
||||
listed on the command line to be run. Here, in addition to the default fixers,
|
||||
the ``idioms`` fixer is run::
|
||||
|
||||
$ 2to3 -f all -f idioms example.py
|
||||
|
||||
Notice how ``all`` enables all default fixers.
|
||||
Notice how passing ``all`` enables all default fixers.
|
||||
|
||||
Sometimes 2to3 will find will find a place in your source code that needs to be
|
||||
changed, but 2to3 cannot fix automatically. In this case, 2to3 will print a
|
||||
warning beneath the diff for a file.
|
||||
warning beneath the diff for a file. You should address the warning in order to
|
||||
have compliant 3.x code.
|
||||
|
||||
2to3 can also refactor doctests. To enable this mode, use the :option:`-d`
|
||||
flag. Note that *only* doctests will be refactored.
|
||||
|
||||
The :option:`-v` option enables the output of more information on the
|
||||
translation process.
|
||||
|
||||
When the :option:`-p` is passed to it, 2to3 treats ``print`` as a function
|
||||
instead of a statement. This is useful when ``from __future__ import
|
||||
print_function`` is being used. If this option is not given, the print fixer
|
||||
will surround print calls in an extra set of parentheses because it cannot
|
||||
differentiate between the and print statement with parentheses (such as ``print
|
||||
("a" + "b" + "c")``) and a true function call.
|
||||
|
||||
|
||||
:mod:`lib2to3` - 2to3's library
|
||||
|
|
|
@ -11,7 +11,12 @@ This module helps scripts to parse the command line arguments in ``sys.argv``.
|
|||
It supports the same conventions as the Unix :cfunc:`getopt` function (including
|
||||
the special meanings of arguments of the form '``-``' and '``--``'). Long
|
||||
options similar to those supported by GNU software may be used as well via an
|
||||
optional third argument. This module provides two functions and an
|
||||
optional third argument.
|
||||
|
||||
A more convenient, flexible, and powerful alternative is the
|
||||
:mod:`optparse` module.
|
||||
|
||||
This module provides two functions and an
|
||||
exception:
|
||||
|
||||
|
||||
|
|
|
@ -1859,7 +1859,7 @@ Joining processes that use queues
|
|||
Bear in mind that a process that has put items in a queue will wait before
|
||||
terminating until all the buffered items are fed by the "feeder" thread to
|
||||
the underlying pipe. (The child process can call the
|
||||
:meth:`Queue.cancel_join` method of the queue to avoid this behaviour.)
|
||||
:meth:`Queue.cancel_join_thread` method of the queue to avoid this behaviour.)
|
||||
|
||||
This means that whenever you use a queue you need to make sure that all
|
||||
items which have been put on the queue will eventually be removed before the
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
|
||||
``optparse`` is a more convenient, flexible, and powerful library for parsing
|
||||
command-line options than ``getopt``. ``optparse`` uses a more declarative
|
||||
command-line options than the old :mod:`getopt` module. ``optparse`` uses a more declarative
|
||||
style of command-line parsing: you create an instance of :class:`OptionParser`,
|
||||
populate it with options, and parse the command line. ``optparse`` allows users
|
||||
to specify options in the conventional GNU/POSIX syntax, and additionally
|
||||
|
@ -92,7 +92,7 @@ argument
|
|||
``sys.argv[1:]``, or of some other list provided as a substitute for
|
||||
``sys.argv[1:]``".
|
||||
|
||||
option
|
||||
option
|
||||
an argument used to supply extra information to guide or customize the execution
|
||||
of a program. There are many different syntaxes for options; the traditional
|
||||
Unix syntax is a hyphen ("-") followed by a single letter, e.g. ``"-x"`` or
|
||||
|
@ -464,7 +464,7 @@ user-friendly (documented) options::
|
|||
action="store_true", dest="verbose", default=True,
|
||||
help="make lots of noise [default]")
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_false", dest="verbose",
|
||||
action="store_false", dest="verbose",
|
||||
help="be vewwy quiet (I'm hunting wabbits)")
|
||||
parser.add_option("-f", "--filename",
|
||||
metavar="FILE", help="write output to FILE"),
|
||||
|
@ -1632,7 +1632,7 @@ arguments::
|
|||
setattr(parser.values, option.dest, value)
|
||||
|
||||
[...]
|
||||
parser.add_option("-c", "--callback",
|
||||
parser.add_option("-c", "--callback", dest="vararg_attr",
|
||||
action="callback", callback=vararg_callback)
|
||||
|
||||
The main weakness with this particular implementation is that negative numbers
|
||||
|
|
|
@ -171,6 +171,8 @@ An :class:`SMTP` instance has the following methods:
|
|||
|
||||
Identify yourself to the SMTP server using ``HELO``. The hostname argument
|
||||
defaults to the fully qualified domain name of the local host.
|
||||
The message returned by the server is stored as the :attr:`helo_resp` attribute
|
||||
of the object.
|
||||
|
||||
In normal operation it should not be necessary to call this method explicitly.
|
||||
It will be implicitly called by the :meth:`sendmail` when necessary.
|
||||
|
@ -180,7 +182,13 @@ An :class:`SMTP` instance has the following methods:
|
|||
|
||||
Identify yourself to an ESMTP server using ``EHLO``. The hostname argument
|
||||
defaults to the fully qualified domain name of the local host. Examine the
|
||||
response for ESMTP option and store them for use by :meth:`has_extn`.
|
||||
response for ESMTP option and store them for use by :meth:`has_extn`.
|
||||
Also sets several informational attributes: the message returned by
|
||||
the server is stored as the :attr:`ehlo_resp` attribute, :attr:`does_esmtp`
|
||||
is set to true or false depending on whether the server supports ESMTP, and
|
||||
:attr:`esmtp_features` will be a dictionary containing the names of the
|
||||
SMTP service extensions this server supports, and their
|
||||
parameters (if any).
|
||||
|
||||
Unless you wish to use :meth:`has_extn` before sending mail, it should not be
|
||||
necessary to call this method explicitly. It will be implicitly called by
|
||||
|
|
|
@ -419,7 +419,7 @@ A :class:`Connection` instance has the following attributes and methods:
|
|||
import sqlite3, os
|
||||
|
||||
con = sqlite3.connect('existing_db.db')
|
||||
full_dump = os.linesep.join([line for line in con.iterdump()])
|
||||
full_dump = os.linesep.join(con.iterdump())
|
||||
f = open('dump.sql', 'w')
|
||||
f.writelines(full_dump)
|
||||
f.close()
|
||||
|
|
|
@ -63,7 +63,7 @@ what it can, adding compatibility functions in a
|
|||
usages that will become unsupported in 3.0.
|
||||
|
||||
Some significant new packages have been added to the standard library,
|
||||
such as the :mod:`multiprocessing` and :mod:`jsonlib` modules, but
|
||||
such as the :mod:`multiprocessing` and :mod:`json` modules, but
|
||||
there aren't many new features that aren't related to Python 3.0 in
|
||||
some way.
|
||||
|
||||
|
@ -623,7 +623,7 @@ versa.)
|
|||
Two other classes, :class:`Pool` and :class:`Manager`, provide
|
||||
higher-level interfaces. :class:`Pool` will create a fixed number of
|
||||
worker processes, and requests can then be distributed to the workers
|
||||
by calling :meth:`apply` or `apply_async` to add a single request,
|
||||
by calling :meth:`apply` or :meth:`apply_async` to add a single request,
|
||||
and :meth:`map` or :meth:`map_async` to add a number of
|
||||
requests. The following code uses a :class:`Pool` to spread requests
|
||||
across 5 worker processes and retrieve a list of results::
|
||||
|
@ -977,10 +977,10 @@ sequence of bytes::
|
|||
bytearray(b'ABC')
|
||||
>>> b = bytearray(u'\u21ef\u3244', 'utf-8')
|
||||
>>> b
|
||||
bytearray(b'\xe2\x87\xaf \xe3\x89\x84')
|
||||
bytearray(b'\xe2\x87\xaf\xe3\x89\x84')
|
||||
>>> b[0] = '\xe3'
|
||||
>>> b
|
||||
bytearray(b'\xe3\x87\xaf \xe3\x89\x84')
|
||||
bytearray(b'\xe3\x87\xaf\xe3\x89\x84')
|
||||
>>> unicode(str(b), 'utf-8')
|
||||
u'\u31ef \u3244'
|
||||
|
||||
|
@ -1975,7 +1975,7 @@ changes, or look through the Subversion logs for all the details.
|
|||
|
||||
* A new function in the :mod:`heapq` module, ``merge(iter1, iter2, ...)``,
|
||||
takes any number of iterables returning data in sorted
|
||||
order, and returns a new iterator that returns the contents of all
|
||||
order, and returns a new generator that returns the contents of all
|
||||
the iterators, also in sorted order. For example::
|
||||
|
||||
heapq.merge([1, 3, 5, 9], [2, 8, 16]) ->
|
||||
|
@ -2014,56 +2014,56 @@ changes, or look through the Subversion logs for all the details.
|
|||
others, the missing values are set to *fillvalue*. For example::
|
||||
|
||||
itertools.izip_longest([1,2,3], [1,2,3,4,5]) ->
|
||||
[(1, 1), (2, 2), (3, 3), (None, 4), (None, 5)]
|
||||
(1, 1), (2, 2), (3, 3), (None, 4), (None, 5)
|
||||
|
||||
``product(iter1, iter2, ..., [repeat=N])`` returns the Cartesian product
|
||||
of the supplied iterables, a set of tuples containing
|
||||
every possible combination of the elements returned from each iterable. ::
|
||||
|
||||
itertools.product([1,2,3], [4,5,6]) ->
|
||||
[(1, 4), (1, 5), (1, 6),
|
||||
(1, 4), (1, 5), (1, 6),
|
||||
(2, 4), (2, 5), (2, 6),
|
||||
(3, 4), (3, 5), (3, 6)]
|
||||
(3, 4), (3, 5), (3, 6)
|
||||
|
||||
The optional *repeat* keyword argument is used for taking the
|
||||
product of an iterable or a set of iterables with themselves,
|
||||
repeated *N* times. With a single iterable argument, *N*-tuples
|
||||
are returned::
|
||||
|
||||
itertools.product([1,2], repeat=3)) ->
|
||||
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
|
||||
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]
|
||||
itertools.product([1,2], repeat=3) ->
|
||||
(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
|
||||
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)
|
||||
|
||||
With two iterables, *2N*-tuples are returned. ::
|
||||
|
||||
itertools(product([1,2], [3,4], repeat=2) ->
|
||||
[(1, 3, 1, 3), (1, 3, 1, 4), (1, 3, 2, 3), (1, 3, 2, 4),
|
||||
itertools.product([1,2], [3,4], repeat=2) ->
|
||||
(1, 3, 1, 3), (1, 3, 1, 4), (1, 3, 2, 3), (1, 3, 2, 4),
|
||||
(1, 4, 1, 3), (1, 4, 1, 4), (1, 4, 2, 3), (1, 4, 2, 4),
|
||||
(2, 3, 1, 3), (2, 3, 1, 4), (2, 3, 2, 3), (2, 3, 2, 4),
|
||||
(2, 4, 1, 3), (2, 4, 1, 4), (2, 4, 2, 3), (2, 4, 2, 4)]
|
||||
(2, 4, 1, 3), (2, 4, 1, 4), (2, 4, 2, 3), (2, 4, 2, 4)
|
||||
|
||||
``combinations(iterable, r)`` returns sub-sequences of length *r* from
|
||||
the elements of *iterable*. ::
|
||||
|
||||
itertools.combinations('123', 2) ->
|
||||
[('1', '2'), ('1', '3'), ('2', '3')]
|
||||
('1', '2'), ('1', '3'), ('2', '3')
|
||||
|
||||
itertools.combinations('123', 3) ->
|
||||
[('1', '2', '3')]
|
||||
('1', '2', '3')
|
||||
|
||||
itertools.combinations('1234', 3) ->
|
||||
[('1', '2', '3'), ('1', '2', '4'), ('1', '3', '4'),
|
||||
('2', '3', '4')]
|
||||
('1', '2', '3'), ('1', '2', '4'), ('1', '3', '4'),
|
||||
('2', '3', '4')
|
||||
|
||||
``permutations(iter[, r])`` returns all the permutations of length *r* of
|
||||
the iterable's elements. If *r* is not specified, it will default to the
|
||||
number of elements produced by the iterable. ::
|
||||
|
||||
itertools.permutations([1,2,3,4], 2) ->
|
||||
[(1, 2), (1, 3), (1, 4),
|
||||
(1, 2), (1, 3), (1, 4),
|
||||
(2, 1), (2, 3), (2, 4),
|
||||
(3, 1), (3, 2), (3, 4),
|
||||
(4, 1), (4, 2), (4, 3)]
|
||||
(4, 1), (4, 2), (4, 3)
|
||||
|
||||
``itertools.chain(*iterables)`` is an existing function in
|
||||
:mod:`itertools` that gained a new constructor in Python 2.6.
|
||||
|
@ -2073,7 +2073,7 @@ changes, or look through the Subversion logs for all the details.
|
|||
all the elements of the second, and so on. ::
|
||||
|
||||
chain.from_iterable([[1,2,3], [4,5,6]]) ->
|
||||
[1, 2, 3, 4, 5, 6]
|
||||
1, 2, 3, 4, 5, 6
|
||||
|
||||
(All contributed by Raymond Hettinger.)
|
||||
|
||||
|
@ -2178,7 +2178,7 @@ changes, or look through the Subversion logs for all the details.
|
|||
:const:`UF_APPEND` to indicate that data can only be appended to the
|
||||
file. (Contributed by M. Levinson.)
|
||||
|
||||
``os.closerange(*low*, *high*)`` efficiently closes all file descriptors
|
||||
``os.closerange(low, high)`` efficiently closes all file descriptors
|
||||
from *low* to *high*, ignoring any errors and not including *high* itself.
|
||||
This function is now used by the :mod:`subprocess` module to make starting
|
||||
processes faster. (Contributed by Georg Brandl; :issue:`1663329`.)
|
||||
|
@ -2311,12 +2311,12 @@ changes, or look through the Subversion logs for all the details.
|
|||
will be ignored, not copied.
|
||||
|
||||
The :mod:`shutil` module also provides an :func:`ignore_patterns`
|
||||
function for use with this new parameter.
|
||||
:func:`ignore_patterns` takes an arbitrary number of glob-style patterns
|
||||
and will ignore any files and directories that match any of these patterns.
|
||||
The following example copies a directory tree, but skips both
|
||||
:file:`.svn` directories and Emacs backup
|
||||
files, which have names ending with '~'::
|
||||
function for use with this new parameter. :func:`ignore_patterns`
|
||||
takes an arbitrary number of glob-style patterns and returns a
|
||||
callable that will ignore any files and directories that match any
|
||||
of these patterns. The following example copies a directory tree,
|
||||
but skips both :file:`.svn` directories and Emacs backup files,
|
||||
which have names ending with '~'::
|
||||
|
||||
shutil.copytree('Doc/library', '/tmp/library',
|
||||
ignore=shutil.ignore_patterns('*~', '.svn'))
|
||||
|
@ -2523,13 +2523,15 @@ changes, or look through the Subversion logs for all the details.
|
|||
|
||||
(Contributed by Dwayne Bailey; :issue:`1581073`.)
|
||||
|
||||
* The :mod:`threading` module API is being changed to use properties such as
|
||||
:attr:`daemon` instead of :meth:`setDaemon` and :meth:`isDaemon` methods, and
|
||||
some methods have been renamed to use underscores instead of camel-case; for
|
||||
example, the :meth:`activeCount` method is renamed to :meth:`active_count`.
|
||||
The 2.6 version of the module supports the same properties and renamed
|
||||
methods, but doesn't remove the old methods. 3.0 also fully supports both
|
||||
APIs, and a date for the deprecation of the old APIs has not been set yet.
|
||||
* The :mod:`threading` module API is being changed to use properties
|
||||
such as :attr:`daemon` instead of :meth:`setDaemon` and
|
||||
:meth:`isDaemon` methods, and some methods have been renamed to use
|
||||
underscores instead of camel-case; for example, the
|
||||
:meth:`activeCount` method is renamed to :meth:`active_count`. Both
|
||||
the 2.6 and 3.0 versions of the module support the same properties
|
||||
and renamed methods, but don't remove the old methods. No date has been set
|
||||
for the deprecation of the old APIs in Python 3.x; the old APIs won't
|
||||
be removed in any 2.x version.
|
||||
(Carried out by several people, most notably Benjamin Peterson.)
|
||||
|
||||
The :mod:`threading` module's :class:`Thread` objects
|
||||
|
@ -2735,15 +2737,15 @@ of these built-in functions that can be imported when writing
|
|||
|
||||
The functions in this module currently include:
|
||||
|
||||
* ``ascii(*obj*)``: equivalent to :func:`repr`. In Python 3.0,
|
||||
* ``ascii(obj)``: equivalent to :func:`repr`. In Python 3.0,
|
||||
:func:`repr` will return a Unicode string, while :func:`ascii` will
|
||||
return a pure ASCII bytestring.
|
||||
|
||||
* ``filter(*predicate*, *iterable*)``,
|
||||
``map(*func*, *iterable1*, ...)``: the 3.0 versions
|
||||
* ``filter(predicate, iterable)``,
|
||||
``map(func, iterable1, ...)``: the 3.0 versions
|
||||
return iterators, unlike the 2.x built-ins which return lists.
|
||||
|
||||
* ``hex(*value*)``, ``oct(*value*)``: instead of calling the
|
||||
* ``hex(value)``, ``oct(value)``: instead of calling the
|
||||
:meth:`__hex__` or :meth:`__oct__` methods, these versions will
|
||||
call the :meth:`__index__` method and convert the result to hexadecimal
|
||||
or octal. :func:`oct` will use the new ``0o`` notation for its
|
||||
|
@ -3210,7 +3212,8 @@ that may require changes to your code:
|
|||
Acknowledgements
|
||||
================
|
||||
|
||||
The author would like to thank the following people for offering suggestions,
|
||||
corrections and assistance with various drafts of this article:
|
||||
Georg Brandl, Steve Brown, Nick Coghlan, Jim Jewett, Antoine Pitrou.
|
||||
The author would like to thank the following people for offering
|
||||
suggestions, corrections and assistance with various drafts of this
|
||||
article: Georg Brandl, Steve Brown, Nick Coghlan, Jim Jewett, Kent
|
||||
Johnson, Chris Lambacher, Antoine Pitrou.
|
||||
|
||||
|
|
|
@ -753,7 +753,7 @@ class StreamHandler(Handler):
|
|||
self.stream.write(fs % msg)
|
||||
else:
|
||||
try:
|
||||
if hasattr(self.stream, 'encoding'):
|
||||
if getattr(self.stream, 'encoding', None) is not None:
|
||||
self.stream.write(fs % msg.encode(self.stream.encoding))
|
||||
else:
|
||||
self.stream.write(fs % msg)
|
||||
|
|
|
@ -19,7 +19,7 @@ Configuration functions for the logging package for Python. The core package
|
|||
is based on PEP 282 and comments thereto in comp.lang.python, and influenced
|
||||
by Apache's log4j system.
|
||||
|
||||
Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved.
|
||||
Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
|
||||
|
||||
To use, simply 'import logging' and log away!
|
||||
"""
|
||||
|
@ -98,6 +98,8 @@ def _resolve(name):
|
|||
found = getattr(found, n)
|
||||
return found
|
||||
|
||||
def _strip_spaces(alist):
|
||||
return map(lambda x: x.strip(), alist)
|
||||
|
||||
def _create_formatters(cp):
|
||||
"""Create and return formatters"""
|
||||
|
@ -105,9 +107,10 @@ def _create_formatters(cp):
|
|||
if not len(flist):
|
||||
return {}
|
||||
flist = flist.split(",")
|
||||
flist = _strip_spaces(flist)
|
||||
formatters = {}
|
||||
for form in flist:
|
||||
sectname = "formatter_%s" % form.strip()
|
||||
sectname = "formatter_%s" % form
|
||||
opts = cp.options(sectname)
|
||||
if "format" in opts:
|
||||
fs = cp.get(sectname, "format", 1)
|
||||
|
@ -133,10 +136,11 @@ def _install_handlers(cp, formatters):
|
|||
if not len(hlist):
|
||||
return {}
|
||||
hlist = hlist.split(",")
|
||||
hlist = _strip_spaces(hlist)
|
||||
handlers = {}
|
||||
fixups = [] #for inter-handler references
|
||||
for hand in hlist:
|
||||
sectname = "handler_%s" % hand.strip()
|
||||
sectname = "handler_%s" % hand
|
||||
klass = cp.get(sectname, "class")
|
||||
opts = cp.options(sectname)
|
||||
if "formatter" in opts:
|
||||
|
@ -189,8 +193,9 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
|
|||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = hlist.split(",")
|
||||
hlist = _strip_spaces(hlist)
|
||||
for hand in hlist:
|
||||
log.addHandler(handlers[hand.strip()])
|
||||
log.addHandler(handlers[hand])
|
||||
|
||||
#and now the others...
|
||||
#we don't want to lose the existing loggers,
|
||||
|
@ -240,8 +245,9 @@ def _install_loggers(cp, handlers, disable_existing_loggers):
|
|||
hlist = cp.get(sectname, "handlers")
|
||||
if len(hlist):
|
||||
hlist = hlist.split(",")
|
||||
hlist = _strip_spaces(hlist)
|
||||
for hand in hlist:
|
||||
logger.addHandler(handlers[hand.strip()])
|
||||
logger.addHandler(handlers[hand])
|
||||
|
||||
#Disable any old loggers. There's no point deleting
|
||||
#them as other threads may continue to hold references
|
||||
|
|
|
@ -587,6 +587,48 @@ class ConfigFileTest(BaseTest):
|
|||
# config5 specifies a custom handler class to be loaded
|
||||
config5 = config1.replace('class=StreamHandler', 'class=logging.StreamHandler')
|
||||
|
||||
# config6 uses ', ' delimiters in the handlers and formatters sections
|
||||
config6 = """
|
||||
[loggers]
|
||||
keys=root,parser
|
||||
|
||||
[handlers]
|
||||
keys=hand1, hand2
|
||||
|
||||
[formatters]
|
||||
keys=form1, form2
|
||||
|
||||
[logger_root]
|
||||
level=WARNING
|
||||
handlers=
|
||||
|
||||
[logger_parser]
|
||||
level=DEBUG
|
||||
handlers=hand1
|
||||
propagate=1
|
||||
qualname=compiler.parser
|
||||
|
||||
[handler_hand1]
|
||||
class=StreamHandler
|
||||
level=NOTSET
|
||||
formatter=form1
|
||||
args=(sys.stdout,)
|
||||
|
||||
[handler_hand2]
|
||||
class=FileHandler
|
||||
level=NOTSET
|
||||
formatter=form1
|
||||
args=('test.blah', 'a')
|
||||
|
||||
[formatter_form1]
|
||||
format=%(levelname)s ++ %(message)s
|
||||
datefmt=
|
||||
|
||||
[formatter_form2]
|
||||
format=%(message)s
|
||||
datefmt=
|
||||
"""
|
||||
|
||||
def apply_config(self, conf):
|
||||
try:
|
||||
fn = tempfile.mktemp(".ini")
|
||||
|
@ -653,6 +695,9 @@ class ConfigFileTest(BaseTest):
|
|||
def test_config5_ok(self):
|
||||
self.test_config1_ok(config=self.config5)
|
||||
|
||||
def test_config6_ok(self):
|
||||
self.test_config1_ok(config=self.config6)
|
||||
|
||||
class LogRecordStreamHandler(StreamRequestHandler):
|
||||
|
||||
"""Handler for a streaming logging request. It saves the log message in the
|
||||
|
@ -814,6 +859,31 @@ class MemoryTest(BaseTest):
|
|||
('foo', 'DEBUG', '3'),
|
||||
])
|
||||
|
||||
class EncodingTest(BaseTest):
|
||||
def test_encoding_plain_file(self):
|
||||
# In Python 2.x, a plain file object is treated as having no encoding.
|
||||
log = logging.getLogger("test")
|
||||
fn = tempfile.mktemp(".log")
|
||||
# the non-ascii data we write to the log.
|
||||
data = "foo\x80"
|
||||
try:
|
||||
handler = logging.FileHandler(fn, encoding="utf8")
|
||||
log.addHandler(handler)
|
||||
try:
|
||||
# write non-ascii data to the log.
|
||||
log.warning(data)
|
||||
finally:
|
||||
log.removeHandler(handler)
|
||||
handler.close()
|
||||
# check we wrote exactly those bytes, ignoring trailing \n etc
|
||||
f = open(fn, encoding="utf8")
|
||||
try:
|
||||
self.failUnlessEqual(f.read().rstrip(), data)
|
||||
finally:
|
||||
f.close()
|
||||
finally:
|
||||
if os.path.isfile(fn):
|
||||
os.remove(fn)
|
||||
|
||||
# Set the locale to the platform-dependent default. I have no idea
|
||||
# why the test does this, but in any case we save the current locale
|
||||
|
@ -822,7 +892,8 @@ class MemoryTest(BaseTest):
|
|||
def test_main():
|
||||
run_unittest(BuiltinLevelsTest, BasicFilterTest,
|
||||
CustomLevelsAndFiltersTest, MemoryHandlerTest,
|
||||
ConfigFileTest, SocketHandlerTest, MemoryTest)
|
||||
ConfigFileTest, SocketHandlerTest, MemoryTest,
|
||||
EncodingTest)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
||||
|
|
|
@ -410,14 +410,14 @@ $(LIBRARY): $(LIBRARY_OBJS)
|
|||
|
||||
libpython$(VERSION).so: $(LIBRARY_OBJS)
|
||||
if test $(INSTSONAME) != $(LDLIBRARY); then \
|
||||
$(LDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \
|
||||
$(LDSHARED) $(LDFLAGS) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
|
||||
$(LN) -f $(INSTSONAME) $@; \
|
||||
else\
|
||||
$(LDSHARED) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \
|
||||
$(LDSHARED) $(LDFLAGS) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \
|
||||
fi
|
||||
|
||||
libpython$(VERSION).sl: $(LIBRARY_OBJS)
|
||||
$(LDSHARED) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM)
|
||||
$(LDSHARED) $(LDFLAGS) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST)
|
||||
|
||||
# This rule is here for OPENSTEP/Rhapsody/MacOSX. It builds a temporary
|
||||
# minimal framework (not including the Lib directory and such) in the current
|
||||
|
@ -451,8 +451,8 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \
|
|||
# for a shared core library; otherwise, this rule is a noop.
|
||||
$(DLLLIBRARY) libpython$(VERSION).dll.a: $(LIBRARY_OBJS)
|
||||
if test -n "$(DLLLIBRARY)"; then \
|
||||
$(LDSHARED) -Wl,--out-implib=$@ -o $(DLLLIBRARY) $^ \
|
||||
$(LIBS) $(MODLIBS) $(SYSLIBS); \
|
||||
$(LDSHARED) $(LDFLAGS) -Wl,--out-implib=$@ -o $(DLLLIBRARY) $^ \
|
||||
$(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST); \
|
||||
else true; \
|
||||
fi
|
||||
|
||||
|
|
Loading…
Reference in New Issue