String changes

This commit is contained in:
Kovid Goyal 2017-04-26 08:16:39 +05:30
parent 3c7f856ddf
commit 1c5eeeae83
8 changed files with 38 additions and 35 deletions

View File

@ -360,7 +360,7 @@ by the conversion pipeline. There is a wizard to help you customize the regular
your document. Click the magic wand beside the expression box, and click the 'Test' button after composing
your search expression. Successful matches will be highlighted in Yellow.
The search works by using a python regular expression. All matched text is simply removed from
The search works by using a Python regular expression. All matched text is simply removed from
the document or replaced using the replacement pattern. The replacement pattern is optional, if left blank
then text matching the search pattern will be deleted from the document. You can learn more about regular expressions
and their syntax at :ref:`regexptutorial`.

View File

@ -294,10 +294,10 @@ The e-book-editor can be started as::
calibre-debug -t /path/to/be/edited
Using an interactive python interpreter
Using an interactive Python interpreter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can insert the following two lines of code to start an interactive python session at that point::
You can insert the following two lines of code to start an interactive Python session at that point::
from calibre import ipython
ipython(locals())
@ -307,10 +307,10 @@ locally defined variables (variables in the local scope). The interactive prompt
for object properties and you can use the various Python facilities for introspection, such as
:func:`dir`, :func:`type`, :func:`repr`, etc.
Using the python debugger as a remote debugger
Using the Python debugger as a remote debugger
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use the builtin python debugger (pdb) as a remote debugger from the
You can use the builtin Python debugger (pdb) as a remote debugger from the
command line. First, start the remote debugger at the point in the calibre code
you are interested in, like this::
@ -326,7 +326,7 @@ the debugging session::
calibre-debug -c "from calibre.rpdb import cli; cli()"
You can read about how to use the python debugger in the `python stdlib docs
You can read about how to use the Python debugger in the `Python stdlib docs
for the pdb module <https://docs.python.org/2/library/pdb.html#debugger-commands>`_.
.. note::
@ -336,13 +336,13 @@ for the pdb module <https://docs.python.org/2/library/pdb.html#debugger-commands
``cli(port=1234)``.
.. note::
The python debugger cannot handle multiple threads, so you have to
The Python debugger cannot handle multiple threads, so you have to
call set_trace once per thread, each time with a different port number.
Using the debugger in your favorite python IDE
Using the debugger in your favorite Python IDE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is possible to use the builtin debugger in your favorite python IDE, if it
It is possible to use the builtin debugger in your favorite Python IDE, if it
supports remote debugging. The first step is to add the calibre src checkout to
the ``PYTHONPATH`` in your IDE. In other words, the directory you set as
``CALIBRE_DEVELOP_FROM`` above, must also be in the ``PYTHONPATH`` of your IDE.
@ -353,15 +353,15 @@ remote debugger to calibre at the point of interest, for example in the main
function. Then run calibre as normal. Your IDE should now be able to connect to
the remote debugger running inside calibre.
Executing arbitrary scripts in the calibre python environment
Executing arbitrary scripts in the calibre Python environment
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :command:`calibre-debug` command provides a couple of handy switches to execute your own
code, with access to the calibre modules::
calibre-debug -c "some python code"
calibre-debug -c "some Python code"
is great for testing a little snippet of code on the command line. It works in the same way as the -c switch to the python interpreter::
is great for testing a little snippet of code on the command line. It works in the same way as the -c switch to the Python interpreter::
calibre-debug myscript.py

View File

@ -254,7 +254,7 @@ expressions in a single operation.
Function mode
^^^^^^^^^^^^^^^^^^^^^
Function mode allows you to write arbitrarily powerful python functions that
Function mode allows you to write arbitrarily powerful Python functions that
are run on every Find/replace. You can do pretty much any text manipulation you
like in function mode. For more information, see :doc:`function_mode`.

View File

@ -3,14 +3,14 @@ Function Mode for Search & Replace in the Editor
The :guilabel:`Search & replace` tool in the editor support a *function mode*.
In this mode, you can combine regular expressions (see :doc:`regexp`) with
arbitrarily powerful python functions to do all sorts of advanced text
arbitrarily powerful Python functions to do all sorts of advanced text
processing.
In the standard *regexp* mode for search and replace, you specify both a
regular expression to search for as well as a template that is used to replace
all found matches. In function mode, instead of using a fixed template, you
specify an arbitrary function, in the
`python programming language <https://docs.python.org/2.7/>`_. This allows
`Python programming language <https://docs.python.org/2.7/>`_. This allows
you to do lots of things that are not possible with simple templates.
Techniques for using function mode and the syntax will be described by means of
@ -45,7 +45,7 @@ the editor leaves individual hyphens alone, so you can use the this function to
replace them with em-dashes.
To create a new function, simply click the :guilabel:`Create/edit` button to create a new
function and copy the python code from below.
function and copy the Python code from below.
.. code-block:: python
@ -53,7 +53,7 @@ function and copy the python code from below.
return match.group().replace('--', '—').replace('-', '—')
Every :guilabel:`Search & replace` custom function must have a unique name and consist of a
python function named replace, that accepts all the arguments shown above.
Python function named replace, that accepts all the arguments shown above.
For the moment, we wont worry about all the different arguments to
``replace()`` function. Just focus on the ``match`` argument. It represents a
match when running a search and replace. Its full documentation in available
@ -206,7 +206,7 @@ HTML Table of Contents, ready to be pasted into :file:`toc.html`.
The function above is heavily commented, so it should be easy to follow. The
key new feature is the use of another useful extra argument to the
``replace()`` function, the ``data`` object. The ``data`` object is a python
``replace()`` function, the ``data`` object. The ``data`` object is a Python
*dict* that persists between all successive invocations of ``replace()`` during
a single :guilabel:`Replace All` operation.
@ -223,7 +223,7 @@ you would be better off using the dedicated Table of Contents tool in
The API for the function mode
-----------------------------
All function mode functions must be python functions named replace, with the
All function mode functions must be Python functions named replace, with the
following signature::
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
@ -239,7 +239,7 @@ The ``match`` argument
^^^^^^^^^^^^^^^^^^^^^^
The ``match`` argument represents the currently found match. It is a
`python Match object <https://docs.python.org/2.7/library/re.html#match-objects>`_.
`Python Match object <https://docs.python.org/2.7/library/re.html#match-objects>`_.
Its most useful method is ``group()`` which can be used to get the matched
text corresponding to individual capture groups in the search regular
expression.
@ -278,7 +278,7 @@ for the current book's language.
The ``data`` argument
^^^^^^^^^^^^^^^^^^^^^
This a simple python ``dict``. When you run
This a simple Python ``dict``. When you run
:guilabel:`Replace All`, every successive match will cause ``replace()`` to be
called with the same ``dict`` as data. You can thus use it to store arbitrary
data between invocations of ``replace()`` during a :guilabel:`Replace All`
@ -331,7 +331,7 @@ Debugging your functions
^^^^^^^^^^^^^^^^^^^^^^^^
You can debug the functions you create by using the standard ``print()``
function from python. The output of print will be displayed in a popup window
function from Python. The output of print will be displayed in a popup window
after the Find/replace has completed. You saw an example of using ``print()``
to output an entire table of contents above.

View File

@ -91,19 +91,19 @@ Now in the :guilabel:`Advanced Mode` of the Custom news sources dialog, you sho
.. image:: images/bbc_advanced.png
:align: center
You can see that the fields from the :guilabel:`Basic mode` have been translated to python code in a straightforward manner. We need to add instructions to this recipe to use the print version of the articles. All that's needed is to add the following two lines:
You can see that the fields from the :guilabel:`Basic mode` have been translated to Python code in a straightforward manner. We need to add instructions to this recipe to use the print version of the articles. All that's needed is to add the following two lines:
.. code-block:: python
def print_version(self, url):
return url.replace('https://', 'https://newsvote.bbc.co.uk/mpapps/pagetools/print/')
This is python, so indentation is important. After you've added the lines, it should look like:
This is Python, so indentation is important. After you've added the lines, it should look like:
.. image:: images/bbc_altered.png
:align: center
In the above, ``def print_version(self, url)`` defines a *method* that is called by calibre for every article. ``url`` is the URL of the original article. What ``print_version`` does is take that url and replace it with the new URL that points to the print version of the article. To learn about `python <https://www.python.org>`_ see the `tutorial <https://docs.python.org/2/tutorial/>`_.
In the above, ``def print_version(self, url)`` defines a *method* that is called by calibre for every article. ``url`` is the URL of the original article. What ``print_version`` does is take that url and replace it with the new URL that points to the print version of the article. To learn about `Python <https://www.python.org>`_ see the `tutorial <https://docs.python.org/2/tutorial/>`_.
Now, click the :guilabel:`Add/update recipe` button and your changes will be saved. Re-download the e-book. You should have a much improved e-book. One of the problems with the new version is that the fonts on the print version webpage are too small. This is automatically fixed when converting to an e-book, but even after the fixing process, the font size of the menus and navigation bar to become too large relative to the article text. To fix this, we will do some more customization, in the next section.
@ -287,7 +287,7 @@ The final new feature is the :meth:`calibre.web.feeds.news.BasicNewsRecipe.prepr
Tips for developing new recipes
---------------------------------
The best way to develop new recipes is to use the command line interface. Create the recipe using your favorite python editor and save it to a file say :file:`myrecipe.recipe`. The `.recipe` extension is required. You can download content using this recipe with the command::
The best way to develop new recipes is to use the command line interface. Create the recipe using your favorite Python editor and save it to a file say :file:`myrecipe.recipe`. The `.recipe` extension is required. You can download content using this recipe with the command::
ebook-convert myrecipe.recipe .epub --test -vv --debug-pipeline debug

View File

@ -84,7 +84,7 @@ If you want only the first two letters of the data, use::
{author_sort:.2} - Only the first two letter of the author sort name
The calibre template language comes from python and for more details on the syntax of these advanced formatting operations, look at the `Python documentation <https://docs.python.org/2/library/string.html#format-string-syntax>`_.
The calibre template language comes from Python and for more details on the syntax of these advanced formatting operations, look at the `Python documentation <https://docs.python.org/2/library/string.html#format-string-syntax>`_.
Advanced features
------------------
@ -121,7 +121,7 @@ The functions available are listed below. Note that the definitive documentation
* ``capitalize()`` -- return the value with the first letter upper case and the rest lower case.
* ``contains(pattern, text if match, text if not match)`` -- checks if field contains matches for the regular expression `pattern`. Returns `text if match` if matches are found, otherwise it returns `text if no match`.
* ``count(separator)`` -- interprets the value as a list of items separated by `separator`, returning the number of items in the list. Most lists use a comma as the separator, but authors uses an ampersand. Examples: `{tags:count(,)}`, `{authors:count(&)}`
* ``format_number(template)`` -- interprets the value as a number and format that number using a python formatting template such as "{0:5.2f}" or "{0:,d}" or "${0:5,.2f}". The field_name part of the template must be a 0 (zero) (the "{0:" in the above examples). See the template language and python documentation for more examples. Returns the empty string if formatting fails.
* ``format_number(template)`` -- interprets the value as a number and format that number using a Python formatting template such as "{0:5.2f}" or "{0:,d}" or "${0:5,.2f}". The field_name part of the template must be a 0 (zero) (the "{0:" in the above examples). See the template language and Python documentation for more examples. Returns the empty string if formatting fails.
* ``human_readable()`` -- expects the value to be a number and returns a string representing that number in KB, MB, GB, etc.
* ``ifempty(text)`` -- if the field is not empty, return the value of the field. Otherwise return `text`.
* ``in_list(separator, pattern, found_val, not_found_val)`` -- interpret the field as a list of items separated by `separator`, comparing the `pattern` against each value in the list. If the pattern matches a value, return `found_val`, otherwise return `not_found_val`.
@ -129,7 +129,7 @@ The functions available are listed below. Note that the definitive documentation
* ``language_strings(lang_codes, localize)`` -- return the strings for the language codes passed in `lang_codes`. If `localize` is zero, return the strings in English. If localize is not zero, return the strings in the language of the current locale. `Lang_codes` is a comma-separated list.
* ``list_item(index, separator)`` -- interpret the field as a list of items separated by `separator`, returning the `index`th item. The first item is number zero. The last item can be returned using `list_item(-1,separator)`. If the item is not in the list, then the empty value is returned. The separator has the same meaning as in the `count` function.
* ``lookup(pattern, field, pattern, field, ..., else_field)`` -- like switch, except the arguments are field (metadata) names, not text. The value of the appropriate field will be fetched and used. Note that because composite columns are fields, you can use this function in one composite field to use the value of some other composite field. This is extremely useful when constructing variable save paths (more later).
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of calibre, these are python-compatible regular expressions.
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of calibre, these are Python-compatible regular expressions.
* ``select(key)`` -- interpret the field as a comma-separated list of items, with the items being of the form "id:value". Find the pair with the id equal to key, and return the corresponding value. This function is particularly useful for extracting a value such as an isbn from the set of identifiers for a book.
* ``shorten(left chars, middle text, right chars)`` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use ``{title:shorten(9,-,5)}``, the result will be `Ancient E-nhoe`. If the field's length is less than ``left chars`` + ``right chars`` + the length of ``middle text``, then the field will be used intact. For example, the title `The Dome` would not be changed.
* ``str_in_list(val, separator, string, found_val, not_found_val)`` -- treat val as a list of items separated by separator, comparing the string against each value in the list. If the string matches a value, return found_val, otherwise return not_found_val. If the string contains separators, then it is also treated as a list and each value is checked.
@ -441,7 +441,7 @@ It would be possible to do the above with no custom columns by putting the progr
User-defined template functions
-------------------------------
You can add your own functions to the template processor. Such functions are written in python, and can be used in any of the three template programming modes. The functions are added by going to Preferences -> Advanced -> Template functions. Instructions are shown in that dialog.
You can add your own functions to the template processor. Such functions are written in Python, and can be used in any of the three template programming modes. The functions are added by going to Preferences -> Advanced -> Template functions. Instructions are shown in that dialog.
Special notes for save/send templates
-------------------------------------

View File

@ -25,7 +25,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
help_text = _('''
<p>Here you can add and remove functions used in template processing. A
template function is written in python. It takes information from the
template function is written in Python. It takes information from the
book, processes it in some way, then returns a string result. Functions
defined here are usable in templates in the same way that builtin
functions are usable. The function must be named <b>evaluate</b>, and
@ -233,4 +233,3 @@ if __name__ == '__main__':
from PyQt5.Qt import QApplication
app = QApplication([])
test_widget('Advanced', 'TemplateFunctions')

View File

@ -141,6 +141,7 @@ def builtin_functions():
if name.startswith('replace_') and callable(obj) and hasattr(obj, 'imports'):
yield obj
_functions = None
@ -175,6 +176,7 @@ def remove_function(name, gui_parent=None):
refresh_boxes()
return True
boxes = []
@ -269,11 +271,11 @@ class FunctionEditor(Dialog):
try:
mod = compile_code(source, self.func_name)
except Exception as err:
return error_dialog(self, _('Invalid python code'), _(
'The code you created is not valid python code, with error: %s') % err, show=True)
return error_dialog(self, _('Invalid Python code'), _(
'The code you created is not valid Python code, with error: %s') % err, show=True)
if not callable(mod.get('replace')):
return error_dialog(self, _('No replace function'), _(
'You must create a python function named replace in your code'), show=True)
'You must create a Python function named replace in your code'), show=True)
user_functions[self.func_name] = source
functions(refresh=True)
refresh_boxes()
@ -290,6 +292,7 @@ def builtin(name, *args):
return func
return f
EMPTY_FUNC = '''\
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):
return ''
@ -365,6 +368,7 @@ def replace_swapcase_ignore_tags(match, number, file_name, metadata, dictionarie
'''Swap the case of the matched text, ignoring the text inside tag definitions.'''
return apply_func_to_html_text(match, swapcase)
if __name__ == '__main__':
app = QApplication([])
FunctionEditor().exec_()