From 1c5eeeae836df4bf6940a99329241775a44e8a8a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 26 Apr 2017 08:16:39 +0530 Subject: [PATCH] String changes --- manual/conversion.rst | 2 +- manual/develop.rst | 22 +++++++++---------- manual/edit.rst | 2 +- manual/function_mode.rst | 18 +++++++-------- manual/news.rst | 8 +++---- manual/template_lang.rst | 8 +++---- .../gui2/preferences/template_functions.py | 3 +-- .../gui2/tweak_book/function_replace.py | 10 ++++++--- 8 files changed, 38 insertions(+), 35 deletions(-) diff --git a/manual/conversion.rst b/manual/conversion.rst index dab8dac1dd..0bc1c92134 100644 --- a/manual/conversion.rst +++ b/manual/conversion.rst @@ -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`. diff --git a/manual/develop.rst b/manual/develop.rst index a1396c1909..0df0519974 100644 --- a/manual/develop.rst +++ b/manual/develop.rst @@ -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 `_. .. note:: @@ -336,13 +336,13 @@ for the pdb module `_. This allows +`Python programming language `_. 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 `_. +`Python Match object `_. 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. diff --git a/manual/news.rst b/manual/news.rst index 6fe0db5cf1..67583776d2 100644 --- a/manual/news.rst +++ b/manual/news.rst @@ -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 `_ see the `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 `_ see the `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 diff --git a/manual/template_lang.rst b/manual/template_lang.rst index cef849ad7c..2528ec618d 100644 --- a/manual/template_lang.rst +++ b/manual/template_lang.rst @@ -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 `_. +The calibre template language comes from Python and for more details on the syntax of these advanced formatting operations, look at the `Python documentation `_. 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 ------------------------------------- diff --git a/src/calibre/gui2/preferences/template_functions.py b/src/calibre/gui2/preferences/template_functions.py index 804f5d0e1d..3ebfe54cc4 100644 --- a/src/calibre/gui2/preferences/template_functions.py +++ b/src/calibre/gui2/preferences/template_functions.py @@ -25,7 +25,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): help_text = _('''

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 evaluate, and @@ -233,4 +233,3 @@ if __name__ == '__main__': from PyQt5.Qt import QApplication app = QApplication([]) test_widget('Advanced', 'TemplateFunctions') - diff --git a/src/calibre/gui2/tweak_book/function_replace.py b/src/calibre/gui2/tweak_book/function_replace.py index 5656ca5dac..0a9741d8c9 100644 --- a/src/calibre/gui2/tweak_book/function_replace.py +++ b/src/calibre/gui2/tweak_book/function_replace.py @@ -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_()