diff --git a/Changelog.yaml b/Changelog.yaml index 9e2088d165..3a74248835 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -4,7 +4,7 @@ # for important features/bug fixes. # Also, each release can have new and improved recipes. -- version: 0.7.39 +- version: 0.7.40 date: 2011-01-14 new features: diff --git a/setup/upload.py b/setup/upload.py index f421ca7e18..54bc8e108c 100644 --- a/setup/upload.py +++ b/setup/upload.py @@ -6,7 +6,7 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, re, cStringIO, base64, httplib, subprocess, hashlib, shutil +import os, re, cStringIO, base64, httplib, subprocess, hashlib, shutil, time from subprocess import check_call from tempfile import NamedTemporaryFile, mkdtemp @@ -160,7 +160,7 @@ class UploadToGoogleCode(Command): return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body) - def upload(self, fname, desc, labels=[]): + def upload(self, fname, desc, labels=[], retry=0): form_fields = [('summary', desc)] form_fields.extend([('label', l.strip()) for l in labels]) @@ -183,6 +183,10 @@ class UploadToGoogleCode(Command): print 'Failed to upload with code %d and reason: %s'%(resp.status, resp.reason) + if retry < 1: + print 'Retrying in 5 seconds....' + time.sleep(5) + return self.upload(fname, desc, labels=labels, retry=retry+1) raise Exception('Failed to upload '+fname) diff --git a/src/calibre/constants.py b/src/calibre/constants.py index e2fe1df942..5c4a228efb 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -2,7 +2,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = 'calibre' -__version__ = '0.7.39' +__version__ = '0.7.40' __author__ = "Kovid Goyal " import re diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index 0910745ac9..7b14de8176 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -92,7 +92,12 @@ class ViewAction(InterfaceAction): formats = [list(f.upper().split(',')) if f else None for f in formats] all_fmts = set([]) for x in formats: - for f in x: all_fmts.add(f) + if x: + for f in x: all_fmts.add(f) + if not all_fmts: + error_dialog(self.gui, _('Format unavailable'), + _('Selected books have no formats'), show=True) + return d = ChooseFormatDialog(self.gui, _('Choose the format to view'), list(sorted(all_fmts))) if d.exec_() == d.Accepted: diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 3b475e8df7..e0c6caa9b5 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: calibre 0.7.39\n" -"POT-Creation-Date: 2011-01-14 12:02+MST\n" -"PO-Revision-Date: 2011-01-14 12:02+MST\n" +"Project-Id-Version: calibre 0.7.40\n" +"POT-Creation-Date: 2011-01-14 15:09+MST\n" +"PO-Revision-Date: 2011-01-14 15:09+MST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -4604,161 +4604,153 @@ msgstr "" #: #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:304 msgid "" -"\n" -"\n" -"

Default pattern

\n" -"

\\[.+\\]

\n" -"

excludes tags of the form [tag],

\n" -"

e.g., [Project Gutenberg]

" +"

Default pattern \n" +"\\[.+\\]\n" +"excludes tags of the form [tag], \n" +"e.g., [Project Gutenberg]

" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:312 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:308 msgid "Excluded genres" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:313 -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:309 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:312 msgid "Tags to &exclude" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:314 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:310 msgid "Books matching either pattern will not be included in generated catalog. " msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:311 msgid "Excluded books" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:313 msgid "" -"\n" -"\n" -"

Comma-separated list of tags to exclude.

\n" -"

Default: ~,Catalog

" +"

Comma-separated list of tags to exclude.\n" +"Default: ~,Catalog" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:323 -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:320 msgid "&Column/value" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:324 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:316 msgid "Column containing additional exclusion criteria" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:325 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:317 msgid "Exclusion pattern" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:326 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:318 msgid "Matching books will be displayed with a check mark" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:319 msgid "Read books" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:329 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:321 msgid "Column containing 'read' status" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:330 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:322 msgid "'read book' pattern" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:323 msgid "Other options" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:324 msgid "&Wishlist tag" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:333 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:325 msgid "Books tagged as Wishlist items will be displayed with an X" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:334 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:326 msgid "&Thumbnail width" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:335 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:327 msgid "Size hint for Description cover thumbnails" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:336 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:328 msgid " inch" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:337 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:329 msgid "&Description note" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:338 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:330 msgid "Custom column source for note to include in Description header area" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:339 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:331 msgid "&Merge with Comments" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:340 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:332 msgid "Additional content merged with Comments during catalog generation" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:341 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:333 msgid "Merge additional content before Comments" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:342 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:334 msgid "&Before" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:343 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:335 msgid "Merge additional content after Comments" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:344 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:336 msgid "&After" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:345 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:337 msgid "Separate Comments and additional content with horizontal rule" msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:346 +#: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi_ui.py:338 msgid "&Separator" msgstr "" @@ -12244,115 +12236,115 @@ msgstr "" msgid "No documentation provided" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:92 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:95 msgid "strcmp(x, y, lt, eq, gt) -- does a case-insensitive comparison of x and y as strings. Returns lt if x < y. Returns eq if x == y. Otherwise returns gt." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:107 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:110 msgid "cmp(x, y, lt, eq, gt) -- compares x and y after converting both to numbers. Returns lt if x < y. Returns eq if x == y. Otherwise returns gt." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:122 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:125 msgid "strcat(a, b, ...) -- can take any number of arguments. Returns a string formed by concatenating all the arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:135 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:138 msgid "add(x, y) -- returns x + y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:145 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:148 msgid "subtract(x, y) -- returns x - y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:155 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:158 msgid "multiply(x, y) -- returns x * y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:165 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:168 msgid "divide(x, y) -- returns x / y. Throws an exception if either x or y are not numbers." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:175 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:178 msgid "template(x) -- evaluates x as a template. The evaluation is done in its own context, meaning that variables are not shared between the caller and the template evaluation. Because the { and } characters are special, you must use [[ for the { character and ]] for the } character; they are converted automatically. For example, template('[[title_sort]]') will evaluate the template {title_sort} and return its value." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:190 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:193 msgid "eval(template) -- evaluates the template, passing the local variables (those 'assign'ed to) instead of the book metadata. This permits using the template processor to construct complex results from local variables." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:203 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:206 msgid "assign(id, val) -- assigns val to id, then returns val. id must be an identifier, not an expression" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:213 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:216 msgid "print(a, b, ...) -- prints the arguments to standard output. Unless you start calibre from the command line (calibre-debug -g), the output will go to a black hole." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:224 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:227 msgid "field(name) -- returns the metadata field named by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:232 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:235 msgid "substr(str, start, end) -- returns the start'th through the end'th characters of str. The first character in str is the zero'th character. If end is negative, then it indicates that many characters counting from the right. If end is zero, then it indicates the last character. For example, substr('12345', 1, 0) returns '2345', and substr('12345', 1, -1) returns '234'." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:245 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:248 msgid "lookup(val, 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" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:260 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:263 msgid "lookup requires either 2 or an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:272 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:275 msgid "test(val, text if not empty, text if empty) -- return `text if not empty` if the field is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:284 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:287 msgid "contains(val, 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`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:299 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:302 msgid "switch(val, pattern, value, pattern, value, ..., else_value) -- for each `pattern, value` pair, checks if the field matches the regular expression `pattern` and if so, returns that `value`. If no pattern matches, then else_value is returned. You can have as many `pattern, value` pairs as you want" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:307 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:310 msgid "switch requires an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:319 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:322 msgid "re(val, 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" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:330 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:333 msgid "ifempty(val, text if empty) -- return val if val is not empty, otherwise return `text if empty`" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:342 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:345 msgid "shorten(val, 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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:367 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:370 msgid "count(val, 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(&)}" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:378 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:381 msgid "list_item(val, index, separator) -- interpret the value 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." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:398 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:401 msgid "uppercase(val) -- return value of the field in upper case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:406 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:409 msgid "lowercase(val) -- return value of the field in lower case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:414 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:417 msgid "titlecase(val) -- return value of the field in title case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:422 +#: /home/kovid/work/calibre/src/calibre/utils/formatter_functions.py:425 msgid "capitalize(val) -- return value of the field capitalized" msgstr "" diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index 7237f227e2..a66d787095 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -83,7 +83,10 @@ class BuiltinFormatterFunction(FormatterFunction): formatter_functions.register_builtin(self) eval_func = inspect.getmembers(self.__class__, lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate') - lines = [l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]] + try: + lines = [l[4:] for l in inspect.getsourcelines(eval_func[0][1])[0]] + except: + lines = [] self.program_text = ''.join(lines) class BuiltinStrcmp(BuiltinFormatterFunction):