mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
News download system: Allow use of __future__ in recipes, and do not change line numbers of code in the recipe when compiling it
This commit is contained in:
parent
1962d12290
commit
959afbd350
@ -4,20 +4,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
Builtin recipes.
|
||||
'''
|
||||
import re, imp, inspect, time, os
|
||||
from calibre.web.feeds.news import BasicNewsRecipe, CustomIndexRecipe, \
|
||||
AutomaticNewsRecipe, CalibrePeriodical
|
||||
import re, time, io
|
||||
from calibre.web.feeds.news import (BasicNewsRecipe, CustomIndexRecipe,
|
||||
AutomaticNewsRecipe, CalibrePeriodical)
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
from calibre import __appname__, english_sort
|
||||
from calibre.utils.config import JSONConfig
|
||||
|
||||
BeautifulSoup, time, english_sort
|
||||
|
||||
basic_recipes = (BasicNewsRecipe, AutomaticNewsRecipe, CustomIndexRecipe,
|
||||
CalibrePeriodical)
|
||||
_tdir = None
|
||||
_crep = 0
|
||||
|
||||
custom_recipes = JSONConfig('custom_recipes/index.json')
|
||||
|
||||
@ -28,39 +22,33 @@ def custom_recipe_filename(id_, title):
|
||||
|
||||
def compile_recipe(src):
|
||||
'''
|
||||
Compile the code in src and return the first object that is a recipe or profile.
|
||||
@param src: Python source code
|
||||
@type src: string
|
||||
@return: Recipe class or None, if no such class was found in C{src}
|
||||
Compile the code in src and return a recipe object, if found.
|
||||
|
||||
:param src: Python source code as bytestring or unicode object
|
||||
|
||||
:return: Recipe class or None, if no such class was found in src
|
||||
'''
|
||||
global _tdir, _crep
|
||||
if _tdir is None or not os.path.exists(_tdir):
|
||||
_tdir = PersistentTemporaryDirectory('_recipes')
|
||||
temp = os.path.join(_tdir, 'recipe%d.py'%_crep)
|
||||
_crep += 1
|
||||
if not isinstance(src, unicode):
|
||||
match = re.search(r'coding[:=]\s*([-\w.]+)', src[:200])
|
||||
enc = match.group(1) if match else 'utf-8'
|
||||
src = src.decode(enc)
|
||||
src = re.sub(r'from __future__.*', '', src)
|
||||
f = open(temp, 'wb')
|
||||
src = 'from %s.web.feeds.news import BasicNewsRecipe, AutomaticNewsRecipe\n'%__appname__ + src
|
||||
src = '# coding: utf-8\n' + src
|
||||
src = 'from __future__ import with_statement\n' + src
|
||||
# Python complains if there is a coding declaration in a unicode string
|
||||
src = re.sub(r'^#.*coding\s*[:=]\s*([-\w.]+)', '#', src, flags=re.MULTILINE)
|
||||
# Translate newlines to \n
|
||||
src = io.StringIO(src, newline=None).getvalue()
|
||||
|
||||
src = src.replace('from libprs500', 'from calibre').encode('utf-8')
|
||||
f.write(src)
|
||||
f.close()
|
||||
module = imp.find_module(os.path.splitext(os.path.basename(temp))[0],
|
||||
[os.path.dirname(temp)])
|
||||
module = imp.load_module(os.path.splitext(os.path.basename(temp))[0], *module)
|
||||
classes = inspect.getmembers(module,
|
||||
lambda x : inspect.isclass(x) and \
|
||||
issubclass(x, (BasicNewsRecipe,)) and \
|
||||
x not in basic_recipes)
|
||||
if not classes:
|
||||
return None
|
||||
namespace = {
|
||||
'BasicNewsRecipe':BasicNewsRecipe,
|
||||
'AutomaticNewsRecipe':AutomaticNewsRecipe,
|
||||
'time':time, 're':re,
|
||||
'BeautifulSoup':BeautifulSoup
|
||||
}
|
||||
exec src in namespace
|
||||
|
||||
return classes[0][1]
|
||||
for x in namespace.itervalues():
|
||||
if (isinstance(x, type) and issubclass(x, BasicNewsRecipe) and x not
|
||||
in basic_recipes):
|
||||
return x
|
||||
|
||||
return None
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user