Merge from trunk

This commit is contained in:
Charles Haley 2011-09-24 12:57:26 +02:00
commit 6c8b994534
11 changed files with 108 additions and 76 deletions

View File

@ -653,6 +653,7 @@ class KindleDXOutput(OutputProfile):
return u'%s <br/><span style="color: white">%s</span>' % (', '.join(tags),
'ttt '.join(tags)+'ttt ')
class IlliadOutput(OutputProfile):
name = 'Illiad'
@ -731,12 +732,23 @@ class BambookOutput(OutputProfile):
fbase = 12
fsizes = [10, 12, 14, 16]
class PocketBook900Output(OutputProfile):
author = 'Chris Lockfort'
name = 'PocketBook Pro 900'
short_name = 'pocketbook_900'
description = _('This profile is intended for the PocketBook Pro 900 series of devices.')
screen_size = (810, 1180)
dpi = 150.0
comic_screen_size = screen_size
output_profiles = [OutputProfile, SonyReaderOutput, SonyReader300Output,
SonyReader900Output, MSReaderOutput, MobipocketOutput, HanlinV3Output,
HanlinV5Output, CybookG3Output, CybookOpusOutput, KindleOutput,
iPadOutput, KoboReaderOutput, TabletOutput, SamsungGalaxy,
SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput,
IRexDR1000Output, IRexDR800Output, JetBook5Output, NookOutput,
BambookOutput, NookColorOutput, GenericEink, GenericEinkLarge]
BambookOutput, NookColorOutput, PocketBook900Output, GenericEink, GenericEinkLarge]
output_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower()))

View File

@ -368,7 +368,7 @@ class MobiMLizer(object):
istate.strikethrough = style['text-decoration'] == 'line-through'
istate.underline = style['text-decoration'] == 'underline'
ff = style['font-family'].lower() if style['font-family'] else ''
if 'monospace' in ff or 'courier' in ff:
if 'monospace' in ff or 'courier' in ff or ff.endswith(' mono'):
istate.family = 'monospace'
elif ('sans-serif' in ff or 'sansserif' in ff or 'verdana' in ff or
'arial' in ff or 'helvetica' in ff):

View File

@ -28,7 +28,7 @@ class Tokenize:
self.__bug_handler = bug_handler
self.__copy = copy
self.__write_to = tempfile.mktemp()
# self.__out_file = out_file
# self.__write_to = out_file
self.__compile_expressions()
#variables
self.__uc_char = 0
@ -41,14 +41,11 @@ class Tokenize:
def __remove_uc_chars(self, startchar, token):
for i in xrange(startchar, len(token)):
#handle the case of an uc char with a terminating blank before ansi char
if token[i] == " " and self.__uc_char:
continue
elif self.__uc_char:
if self.__uc_char:
self.__uc_char -= 1
else:
return token[i:]
#if only " " and char to skip
#if only char to skip
return ''
def __unicode_process(self, token):
@ -90,7 +87,7 @@ class Tokenize:
self.__reini_utf8_counters()
#get value and handle negative case
uni_char = int(match_obj.group(1))
uni_len = len(match_obj.group(1)) + 2
uni_len = len(match_obj.group(0))
if uni_char < 0:
uni_char += 65536
uni_char = unichr(uni_char).encode('ascii', 'xmlcharrefreplace')
@ -199,7 +196,7 @@ class Tokenize:
# import sys
# def main(args=sys.argv):
# if len(args) < 1:
# if len(args) < 2:
# print 'No file'
# return
# file = 'data_tokens.txt'
@ -211,3 +208,5 @@ class Tokenize:
# if __name__ == '__main__':
# sys.exit(main())
# calibre-debug -e src/calibre/ebooks/rtf2xml/tokenize.py

View File

@ -18,7 +18,6 @@ class ToolBar(QToolBar): # {{{
def __init__(self, donate, location_manager, parent):
QToolBar.__init__(self, parent)
self.setContextMenuPolicy(Qt.PreventContextMenu)
self.setMovable(False)
self.setFloatable(False)
self.setOrientation(Qt.Horizontal)
@ -53,8 +52,14 @@ class ToolBar(QToolBar): # {{{
style = Qt.ToolButtonIconOnly
return style
def contextMenuEvent(self, *args):
pass
def contextMenuEvent(self, ev):
ac = self.actionAt(ev.pos())
if ac is None: return
ch = self.widgetForAction(ac)
sm = getattr(ch, 'showMenu', None)
if callable(sm):
ev.accept()
sm()
def update_lm_actions(self):
for ac in self.added_actions:

View File

@ -170,7 +170,11 @@ class GuiRunner(QObject):
sys.excepthook = main.unhandled_exception
if len(self.args) > 1:
p = os.path.abspath(self.args[1])
add_filesystem_book(p)
if os.path.isdir(p):
prints('Ignoring directory passed as command line argument:',
self.args[1])
else:
add_filesystem_book(p)
self.app.file_event_hook = add_filesystem_book
self.main = main

View File

@ -208,6 +208,12 @@ class PocketBook(CybookG3):
id = 'pocketbook'
output_profile = 'cybookg3'
class PocketBook900(PocketBook):
name = 'PocketBook 900'
id = 'pocketbook900'
output_profile = 'pocketbook_900'
class iPhone(Device):
name = 'iPad or iPhone/iTouch + Stanza'

View File

@ -185,7 +185,7 @@ The first, most important step is to run |app| in debug mode. You can do this fr
calibre-debug -g
Or from within calibre by clicking the arrow next to the preferences button or using the `Ctrl+Shift+R` keyboard shortcut.
Or from within calibre by right-clicking the preferences button or using the `Ctrl+Shift+R` keyboard shortcut.
When running from the command line, debug output will be printed to the console, when running from within |app| the output will go to a txt file.

View File

@ -466,9 +466,9 @@ How do I move my |app| library from one computer to another?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Simply copy the |app| library folder from the old to the new computer. You can find out what the library folder is by clicking the calibre icon in the toolbar. The very first item is the path to the library folder. Now on the new computer, start |app| for the first time. It will run the Welcome Wizard asking you for the location of the |app| library. Point it to the previously copied folder. If the computer you are transferring to already has a calibre installation, then the Welcome wizard wont run. In that case, click the calibre icon in the tooolbar and point it to the newly copied directory. You will now have two calibre libraries on your computer and you can switch between them by clicking the calibre icon on the toolbar.
Note that if you are transferring between different types of computers (for example Windows to OS X) then after doing the above you should also click the arrow next to the calibre icon on the tool bar, select Library Maintenance and run the Check Library action. It will warn you about any problems in your library, which you should fix by hand.
Note that if you are transferring between different types of computers (for example Windows to OS X) then after doing the above you should also right-click the calibre icon on the tool bar, select Library Maintenance and run the Check Library action. It will warn you about any problems in your library, which you should fix by hand.
.. note:: A |app| library is just a folder which contains all the book files and their metadata. All the metadata is stored in a single file called metadata.db, in the top level folder. If this file gets corrupted, you may see an empty list of books in |app|. In this case you can ask |app| to restore your books by clicking the arrow next to the |app| icon on the toolbar and selecting Library Maintenance->Restore Library.
.. note:: A |app| library is just a folder which contains all the book files and their metadata. All the metadata is stored in a single file called metadata.db, in the top level folder. If this file gets corrupted, you may see an empty list of books in |app|. In this case you can ask |app| to restore your books by doing a right-click on the |app| icon in the toolbar and selecting Library Maintenance->Restore Library.
The list of books in |app| is blank!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -477,9 +477,9 @@ In order to understand why that happened, you have to understand what a |app| li
There can be two reasons why |app| is showing a empty list of books:
* Your |app| library folder changed its location. This can happen if it was on an external disk and the drive letter for that disk changed. Or if you accidentally moved the folder. In this case, |app| cannot find its library and so starts up with an empty library instead. To remedy this, simply click the arrow next to the |app| icon in the |app| toolbar (it will say 0 books underneath it) and select Switch/create library. Click the little blue icon to select the new location of your |app| library and click OK.
* Your |app| library folder changed its location. This can happen if it was on an external disk and the drive letter for that disk changed. Or if you accidentally moved the folder. In this case, |app| cannot find its library and so starts up with an empty library instead. To remedy this, do a right-click on the |app| icon in the |app| toolbar (it will say 0 books underneath it) and select Switch/create library. Click the little blue icon to select the new location of your |app| library and click OK.
* Your metadata.db file was deleted/corrupted. In this case, you can ask |app| to rebuild the metadata.db from its backups. Click the arrow next to the |app| icon in the |app| toolbar (it will say 0 books underneath it) and select Library maintenance->Restore database. |app| will automatically rebuild metadata.db.
* Your metadata.db file was deleted/corrupted. In this case, you can ask |app| to rebuild the metadata.db from its backups. Click-and-hold the |app| icon in the |app| toolbar (it will say 0 books underneath it) and select Library maintenance->Restore database. |app| will automatically rebuild metadata.db.
Content From The Web
@ -632,7 +632,7 @@ Can I have the comment metadata show up on my reader?
Most readers do not support this. You should complain to the manufacturer about it and hopefully if enough people complain, things will change. In the meantime, you can insert the metadata, including comments into a "Jacket page" at the start of the ebook, by using the option to "Insert metadata as page at start of book" during conversion. The option is found in the :guilabel:`Structure Detection` section of the conversion settings. Note that for this to have effect you have to *convert* the book. If your book is already in a format that does not need conversion, you can convert from that format to the same format.
Another alternative is to create a catalog in ebook form containing a listing of all the books in your calibre library, with their metadata. Click the arrow next to the convert button to access the catalog creation tool. And before you ask, no you cannot have the catalog "link directly to" books on your reader.
Another alternative is to create a catalog in ebook form containing a listing of all the books in your calibre library, with their metadata. Click-and-hold the convert button to access the catalog creation tool. And before you ask, no you cannot have the catalog "link directly to" books on your reader.
How do I get |app| to use my HTTP proxy?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -30,7 +30,8 @@ Actions
:alt: The Actions Toolbar
:align: center
The actions toolbar provides convenient shortcuts to commonly used actions. Most of the action buttons have little arrows next to them. By clicking the arrows, you can perform variations on the default action. Please note that the actions toolbar will look slightly different depending on whether you have an ebook reader attached to your computer.
The actions toolbar provides convenient shortcuts to commonly used actions. If you right-click the buttons, you can perform variations on the default action.
Please note that the actions toolbar will look slightly different depending on whether you have an ebook reader attached to your computer.
.. contents::
:depth: 1
@ -43,7 +44,7 @@ Add books
.. |adbi| image:: images/add_books.png
:class: float-right-img
|adbi| The :guilabel:`Add books` action has six variations accessed by the clicking the down arrow on the right side of the button.
|adbi| The :guilabel:`Add books` action has six variations accessed by doing a right-click on the button.
1. **Add books from a single directory**: Opens a file chooser dialog and allows you to specify which books in a directory should be added. This action is *context sensitive*, i.e. it depends on which :ref:`catalog <catalogs>` you have selected. If you have selected the :guilabel:`Library`, books will be added to the library. If you have selected the ebook reader device, the books will be uploaded to the device, and so on.
@ -70,7 +71,7 @@ Edit metadata
.. |emii| image:: images/edit_meta_information.png
:class: float-right-img
|emii| The :guilabel:`Edit metadata` action has four variations which can be accessed by clicking the down arrow on the right side of the button.
|emii| The :guilabel:`Edit metadata` action has four variations which can be accessed by doing a right-click on the button.
1. **Edit metadata individually**: Allows you to edit the metadata of books one-by-one with the option of fetching metadata, including covers, from the Internet. It also allows you to add or remove particular ebook formats from a book.
2. **Edit metadata in bulk**: Allows you to edit common metadata fields for large numbers of books simulataneously. It operates on all the books you have selected in the :ref:`Library view <search_sort>`.
@ -93,7 +94,7 @@ you will have to find tools to liberate your books yourself and then use |app| t
For most people, conversion should be a simple one-click affair. If you want to learn more about the conversion process, see :ref:`conversion`.
The :guilabel:`Convert books` action has three variations, accessed by the arrow next to the button.
The :guilabel:`Convert books` action has three variations, accessed by doing a right-click on the button.
1. **Convert individually**: Allows you to specify conversion options to customize the conversion of each selected ebook.
@ -116,8 +117,7 @@ View
|vi| The :guilabel:`View` action displays the book in an ebook viewer program. |app| has a built-in viewer for many ebook formats.
For other formats it uses the default operating system application. You can configure which formats should open with the internal viewer via
Preferences->Behavior. If a book has more than one format, you can view a particular format by clicking the down arrow
on the right of the :guilabel:`View` button.
Preferences->Behavior. If a book has more than one format, you can view a particular format by doing a right-click on the button.
.. _send_to_device:
@ -127,7 +127,7 @@ Send to device
.. |stdi| image:: images/send_to_device.png
:class: float-right-img
|stdi| The :guilabel:`Send to device` action has eight variations, accessed by clicking the down arrow on the right of the button.
|stdi| The :guilabel:`Send to device` action has eight variations, accessed by doing a right-click on the button.
1. **Send to main memory**: The selected books are transferred to the main memory of the ebook reader.
2. **Send to card (A)**: The selected books are transferred to the storage card (A) on the ebook reader.
@ -152,7 +152,7 @@ Fetch news
The :guilabel:`Fetch news` action uses simple recipes (10-15 lines of code) for each news site. To learn how to create recipes for your own news sources, see :ref:`news`.
The :guilabel:`Fetch news` action has three variations, accessed by clicking the down arrow on the right of the button.
The :guilabel:`Fetch news` action has three variations, accessed by doing a right-click on the button.
1. **Schedule news download**: Allows you to schedule the download of of your selected news sources from a list of hundreds available. Scheduling can be set individually for each news source you select and the scheduling is flexible allowing you to select specific days of the week or a frequency of days between downloads.
2. **Add a custom news source**: Allows you to create a simple recipe for downloading news from a custom news site that you wish to access. Creating the recipe can be as simple as specifying an RSS news feed URL, or you can be more prescriptive by creating Python-based code for the task. For more information see :ref:`news`.
@ -197,7 +197,7 @@ Save to disk
.. |svdi| image:: images/save_to_disk.png
:class: float-right-img
|svdi| The :guilabel:`Save to disk` action has five variations, accessed by the arrow next to the button.
|svdi| The :guilabel:`Save to disk` action has five variations, accessed by doing a right-click on the button.
.. _save_to_disk_multiple:
@ -231,7 +231,7 @@ Connect/Share
|csi| The :guilabel:`Connect/Share` action allows you to manually connect to a device or folder on your computer. It also allows you to set up you |app| library for access via a web browser or email.
The :guilabel:`Connect/Share` action has four variations, accessed by clicking the down arrow on the right of the button.
The :guilabel:`Connect/Share` action has four variations, accessed by doing a right-click on the button.
1. **Connect to folder**: Allows you to connect to any folder on your computer as though it were a device and use all the facilities |app| has for devices with that folder. Useful if your device cannot be supported by |app| but is available as a USB disk.
@ -248,7 +248,7 @@ Remove books
.. |rbi| image:: images/remove_books.png
:class: float-right-img
|rbi| The :guilabel:`Remove books` action **deletes books permanently**, so use it with care. It is *context sensitive*, i.e. it depends on which :ref:`catalog <catalogs>` you have selected. If you have selected the :guilabel:`Library`, books will be removed from the library. If you have selected the ebook reader device, books will be removed from the device. To remove only a particular format for a given book use the :ref:`edit_meta_information` action. Remove books also has five variations which can be accessed by clicking the down arrow on the right side of the button.
|rbi| The :guilabel:`Remove books` action **deletes books permanently**, so use it with care. It is *context sensitive*, i.e. it depends on which :ref:`catalog <catalogs>` you have selected. If you have selected the :guilabel:`Library`, books will be removed from the library. If you have selected the ebook reader device, books will be removed from the device. To remove only a particular format for a given book use the :ref:`edit_meta_information` action. Remove books also has five variations which can be accessed by doing a right-click on the button.
1. **Remove selected books**: Allows you to **permanently** remove all books that are selected in the book list.
@ -272,7 +272,7 @@ Preferences
.. |cbi| image:: images/preferences.png
:class: float-right-img
|cbi| The :guilabel:`Preferences` action allows you to change the way various aspects of |app| work. It has four variations, accessed by clicking the down arrow on the right of the button.
|cbi| The :guilabel:`Preferences` action allows you to change the way various aspects of |app| work. It has four variations, accessed by doing a right-click on the button.
1. **Preferences**: Allows you to change the way various aspects of |app| work. Clicking the button also performs this action.
2. **Run welcome wizard**: Allows you to start the Welcome Wizard which appeared the first time you started |app|.

View File

@ -47,7 +47,9 @@ In addition, there is a button to automatically trim borders from the cover, in
Editing the metadata of many books at a time
---------------------------------------------
First select the books you want to edit by holding Ctrl or Shift and clicking on them. If you select more than one book, clicking the :guilabel:`Edit metadata` button will cause a new *Bulk* metadata edit dialog to open. Using this dialog, you can quickly set the author/publisher/rating/tags/series etc of a bunch of books to the same value. This is particularly useful if you have just imported a number of books that have some metadata in common. You can also click the arrow next to the :guilabel:`Edit metadata` button and select :guilabel:`Edit metadata individually` to use the powerful single book edit dialog from above for all the selected books in succession.
First select the books you want to edit by holding Ctrl or Shift and clicking on them. If you select more than one book, clicking the :guilabel:`Edit metadata` button will cause a new *Bulk* metadata edit dialog to open. Using this dialog, you can quickly set the author/publisher/rating/tags/series etc of a bunch of books to the same value. This is particularly useful if you have just imported a number of books that have some metadata in common. This dialog is very powerful, for example, it has a Search and Replace tab that you can use to perform bulk operations on metadata and even copy metadata from one column to another.
The normal edit metadata dialog also has Next and Previous buttons that you can use to edit the metadata of several books one after the other.
Search and replace
^^^^^^^^^^^^^^^^^^^^
@ -81,6 +83,6 @@ Search and replace is done after all the other metadata changes in the other tab
Bulk downloading of metadata
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you want to download the metadata for multiple books at once, click the arrow next to the :guilabel:`Edit metadata` button and select :guilabel:`Download metadata and covers`. You can choose to download only metadata, only covers, both or only social metadata (tags/rating/series).
If you want to download the metadata for multiple books at once, right-click the :guilabel:`Edit metadata` button and select :guilabel:`Download metadata`. You can choose to download only metadata, only covers, or both.

View File

@ -10,28 +10,28 @@ from cherrypy.lib import http as _http
class VirtualHost(object):
"""Select a different WSGI application based on the Host header.
This can be useful when running multiple sites within one CP server.
It allows several domains to point to different applications. For example:
root = Root()
RootApp = cherrypy.Application(root)
Domain2App = cherrypy.Application(root)
SecureApp = cherrypy.Application(Secure())
vhost = cherrypy._cpwsgi.VirtualHost(RootApp,
domains={'www.domain2.example': Domain2App,
'www.domain2.example:443': SecureApp,
})
cherrypy.tree.graft(vhost)
default: required. The default WSGI application.
use_x_forwarded_host: if True (the default), any "X-Forwarded-Host"
request header will be used instead of the "Host" header. This
is commonly added by HTTP servers (such as Apache) when proxying.
domains: a dict of {host header value: application} pairs.
The incoming "Host" request header is looked up in this dict,
and, if a match is found, the corresponding WSGI application
@ -39,17 +39,17 @@ class VirtualHost(object):
separate entries for "example.com" and "www.example.com".
In addition, "Host" headers may contain the port number.
"""
def __init__(self, default, domains=None, use_x_forwarded_host=True):
self.default = default
self.domains = domains or {}
self.use_x_forwarded_host = use_x_forwarded_host
def __call__(self, environ, start_response):
domain = environ.get('HTTP_HOST', '')
if self.use_x_forwarded_host:
domain = environ.get("HTTP_X_FORWARDED_HOST", domain)
nextapp = self.domains.get(domain)
if nextapp is None:
nextapp = self.default
@ -61,10 +61,10 @@ class VirtualHost(object):
class AppResponse(object):
throws = (KeyboardInterrupt, SystemExit)
request = None
def __init__(self, environ, start_response, cpapp, recursive=False):
self.redirections = []
self.recursive = recursive
@ -72,7 +72,7 @@ class AppResponse(object):
self.start_response = start_response
self.cpapp = cpapp
self.setapp()
def setapp(self):
try:
self.request = self.get_request()
@ -91,14 +91,14 @@ class AppResponse(object):
if getattr(self.request, "throw_errors", False):
self.close()
raise
tb = _cperror.format_exc()
_cherrypy.log(tb, severity=40)
if not getattr(self.request, "show_tracebacks", True):
tb = ""
s, h, b = _cperror.bare_error(tb)
self.iter_response = iter(b)
try:
self.start_response(s, h, _sys.exc_info())
except:
@ -110,10 +110,10 @@ class AppResponse(object):
_cherrypy.log(traceback=True, severity=40)
self.close()
raise
def iredirect(self, path, query_string):
"""Doctor self.environ and perform an internal redirect.
When cherrypy.InternalRedirect is raised, this method is called.
It rewrites the WSGI environ using the new path and query_string,
and calls a new CherryPy Request object. Because the wsgi.input
@ -123,7 +123,7 @@ class AppResponse(object):
formed from InternalRedirect.query_string when using that exception.
If you need something more complicated, make and raise your own
exception and write your own AppResponse subclass to trap it. ;)
It would be a bad idea to redirect after you've already yielded
response content, although an enterprising soul could choose
to abuse this.
@ -145,19 +145,19 @@ class AppResponse(object):
if qs:
qs = "?" + qs
self.redirections.append(sn + p + qs)
# Munge environment and try again.
env['REQUEST_METHOD'] = "GET"
env['PATH_INFO'] = path
env['QUERY_STRING'] = query_string
env['wsgi.input'] = _StringIO.StringIO()
env['CONTENT_LENGTH'] = "0"
self.setapp()
def __iter__(self):
return self
def next(self):
try:
chunk = self.iter_response.next()
@ -180,7 +180,7 @@ class AppResponse(object):
if getattr(self.request, "throw_errors", False):
self.close()
raise
tb = _cperror.format_exc()
_cherrypy.log(tb, severity=40)
if not getattr(self.request, "show_tracebacks", True):
@ -188,7 +188,7 @@ class AppResponse(object):
s, h, b = _cperror.bare_error(tb)
# Empty our iterable (so future calls raise StopIteration)
self.iter_response = iter([])
try:
self.start_response(s, h, _sys.exc_info())
except:
@ -200,13 +200,13 @@ class AppResponse(object):
_cherrypy.log(traceback=True, severity=40)
self.close()
raise
return "".join(b)
def close(self):
"""Close and de-reference the current request and response. (Core)"""
self.cpapp.release_serving()
def get_response(self):
"""Run self.request and return its response."""
meth = self.environ['REQUEST_METHOD']
@ -218,11 +218,11 @@ class AppResponse(object):
rfile = self.environ['wsgi.input']
response = self.request.run(meth, path, qs, rproto, headers, rfile)
return response.status, response.header_list, response.body
def get_request(self):
"""Create a Request object using environ."""
env = self.environ.get
local = _http.Host('', int(env('SERVER_PORT', 80)),
env('SERVER_NAME', ''))
remote = _http.Host(env('REMOTE_ADDR', ''),
@ -231,7 +231,7 @@ class AppResponse(object):
scheme = env('wsgi.url_scheme')
sproto = env('ACTUAL_SERVER_PROTOCOL', "HTTP/1.1")
request, resp = self.cpapp.get_serving(local, remote, scheme, sproto)
# LOGON_USER is served by IIS, and is the name of the
# user after having been mapped to a local account.
# Both IIS and Apache set REMOTE_USER, when possible.
@ -241,14 +241,14 @@ class AppResponse(object):
request.wsgi_environ = self.environ
request.prev = env('cherrypy.previous_request', None)
return request
headerNames = {'HTTP_CGI_AUTHORIZATION': 'Authorization',
'CONTENT_LENGTH': 'Content-Length',
'CONTENT_TYPE': 'Content-Type',
'REMOTE_HOST': 'Remote-Host',
'REMOTE_ADDR': 'Remote-Addr',
}
def translate_headers(self, environ):
"""Translate CGI-environ header names to HTTP header names."""
for cgiName in environ:
@ -263,43 +263,47 @@ class AppResponse(object):
class CPWSGIApp(object):
"""A WSGI application object for a CherryPy Application.
pipeline: a list of (name, wsgiapp) pairs. Each 'wsgiapp' MUST be a
constructor that takes an initial, positional 'nextapp' argument,
plus optional keyword arguments, and returns a WSGI application
(that takes environ and start_response arguments). The 'name' can
be any you choose, and will correspond to keys in self.config.
head: rather than nest all apps in the pipeline on each call, it's only
done the first time, and the result is memoized into self.head. Set
this to None again if you change self.pipeline after calling self.
config: a dict whose keys match names listed in the pipeline. Each
value is a further dict which will be passed to the corresponding
named WSGI callable (from the pipeline) as keyword arguments.
"""
pipeline = []
head = None
config = {}
response_class = AppResponse
def __init__(self, cpapp, pipeline=None):
self.cpapp = cpapp
self.pipeline = self.pipeline[:]
if pipeline:
self.pipeline.extend(pipeline)
self.config = self.config.copy()
def tail(self, environ, start_response):
"""WSGI application callable for the actual CherryPy application.
You probably shouldn't call this; call self.__call__ instead,
so that any WSGI middleware in self.pipeline can run first.
"""
# Changed by Kovid as the routes dispatcher cannot handle an empty
# PATH_INFO
if not environ.get('PATH_INFO', True):
environ['PATH_INFO'] = '/'
return self.response_class(environ, start_response, self.cpapp)
def __call__(self, environ, start_response):
head = self.head
if head is None:
@ -311,7 +315,7 @@ class CPWSGIApp(object):
head = callable(head, **conf)
self.head = head
return head(environ, start_response)
def namespace_handler(self, k, v):
"""Config handler for the 'wsgi' namespace."""
if k == "pipeline":