Pull from trunk

This commit is contained in:
Kovid Goyal 2009-05-13 18:38:39 -07:00
commit 0be9db0630
31 changed files with 1144 additions and 464 deletions

355
copyright Normal file
View File

@ -0,0 +1,355 @@
Format-Specification: http://wiki.debian.org/Proposals/CopyrightFormat?action=recall&rev=196
Upstream-Name: calibre
Upstream-Maintainer: Kovid Goyal <kovid@kovidgoyal.net>
Upstream-Source: http://calibre.kovidgoyal.net/downloads
Files: *
Copyright: Copyright (C) 2008 Kovid Goyal <kovid@kovidgoyal.net>
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/BeautifulSoup.py
Copyright: Copyright (c) 2004-2007, Leonard Richardson
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/ebooks/chardet/*
Copyright: Copyright (C) 1998-2001 Netscape Communications Corporation
License: LGPL-2.1+
The full text of the LGPL is distributed as in
/usr/share/common-licenses/LGPL-2.1 on Debian systems.
Files: src/calibre/ebooks/hyphenate.py
Copyright: Copyright (C) 1990, 2004, 2005 Gerard D.C. Kuiken.
License: other
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved.
Files: /src/cherrypy/*
Copyright: Copyright (c) 2004-2007, CherryPy Team (team@cherrypy.org)
Copyright: Copyright (C) 2005, Tiago Cogumbreiro <cogumbreiro@users.sf.net>
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/odf/*
Copyright: Copyright (C) 2006-2008 Søren Roug, European Environment Agency
License: LGPL2.1+
The full text of the LGPL is distributed as in
/usr/share/common-licenses/LGPL-2.1 on Debian systems.
Files: src/odf/teletype.py
Files: src/odf/easyliststyle.py
Copyright: Copyright (C) 2008, J. David Eisenberg
License: GPL2+
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-2 on Debian systems.
Files: src/pyPdf/*
Copyright: Copyright (c) 2006, Mathieu Fenniak
Copyright: Copyright (c) 2007, Ashish Kulkarni <kulkarni.ashish@gmail.com>
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/utils/genshi/*
Copyright: Copyright (C) 2006-2008 Edgewall Software
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/utils/lzx/*
Copyright: Copyright (C) 2002, Matthew T. Russotto
Copyright: Copyright (C) 2008, Marshall T. Vandegrift <llasram@gmail.com>
Copyright: Copyright (C) 2006-2008, Alexander Chemeris
License: LGPL-2.1
The full text of the LGPL is distributed as in
/usr/share/common-licenses/LGPL-2.1 on Debian systems.
Files: src/calibre/utils/lzx/msstdint.h
Copyright: Copyright (C) 2006-2008, Alexander Chemeris
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/utils/pyparsing.py
Copyright: Copyright (c) 2003-2008, Paul T. McGuire
License: MIT
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Files: src/calibre/utils/PythonMagickWand.py
Copyright: (c) 2007 - Achim Domma - domma@procoders.net
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Files: src/calibre/utils/msdes/d3des.h:
Files: src/calibre/utils/msdes/des.c:
Copyright: Copyright (C) 1988,1989,1990,1991,1992, Richard Outerbridge
License: Other
THIS SOFTWARE PLACED IN THE PUBLIC DOMAIN BY THE AUTHOUR
Files: src/calibre/utils/msdes/msdesmodule.c
Copyright: Copyright (C) 2008, Marshall T. Vandegrift <llasram@gmail.com>
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/utils/msdes/spr.h
Copyright: Copyright (C) 2002, Dan A. Jackson
License: GPL2+
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-2 on Debian systems.
Files: src/calibre/gui2/pictureflow/*
Copyright: (C) Copyright 2007 Trolltech ASA
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/ebooks/lit/*
Copyright: 2008, Marshall T. Vandegrift <llasram@gmail.com>
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/lrf/*
Copyright: 2008, Anatoly Shipitsin <norguhtar at gmail.com>
Copyright: copyright 2002 Paul Henry Tremblay
Copyright: Copyright (C) 2008 B.Scott Wxby [bswxby]
Copyright: Copyright (C) 2007 David Chen SonyReader<at>DaveChen<dot>org
Copyright: Copyright (c) 2007 Mike Higgins (Falstaff)
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/BeautifulSoup.py
Copyright: Copyright (c) 2004-2007, Leonard Richardson
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/ebooks/rtf2xml/*
Copyright: copyright 2002 Paul Henry Tremblay
License: GPL
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL on Debian systems.
Files: src/calibre/web/feeds/feedparser.py
Copyright: Copyright (c) 2002-2006, Mark Pilgrim
License: BSD
The full text of the BSD license is distributed as in
/usr/share/common-licenses/BSD on Debian systems.
Files: src/calibre/web/feeds/recipes/*
Copyright: 2008, Darko Miletic <darko.miletic at gmail.com>
Copyright: 2008, Mathieu Godlewski <mathieu at godlewski.fr>
Copyright: Copyright (C) 2008 B.Scott Wxby [bswxby]
Copyright: Copyright (C) 2007 David Chen SonyReader<at>DaveChen<dot>org
Copyright: 2008, Derry FitzGerald
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/ebooks/metadata/*
Copyright: 2008, Ashish Kulkarni <kulkarni.ashish@gmail.com>
Copyright: Copyright (C) 2006 Søren Roug, European Environment Agency
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/encutils/__init__.py
Copyright: 2005-2008: Christof Hoeke
License: LGPL-3+, CC-BY-3.0
The full text of the LGPL is distributed as in
/usr/share/common-licenses/LGPL-3 on Debian systems.
Files: src/calibre/translations/*
Copyright: Copyright (C) 2007, Kovid Goyal
Copyright: Copyright (C) 2008, Rosetta Contributors and Canonical Ltd.
License: GPL-3
The full text of the GPL is distributed as in
/usr/share/common-licenses/GPL-3 on Debian systems.
Files: src/calibre/gui2/viewer/jquery.js
Files: src/calibre/gui2/viewer/jquery_scrollTo.js
Files: src/calibre/library/static/date.js
Copyright: Copyright (C) 2008, John Resig (jquery.com)
Copyright: Copyright (C) 2007-2008, Ariel Flesler - aflesler@gmail.com | http://flesler.blogspot.com
Copyright: Copyright (C) 2006-2007, Coolite Inc. (http://www.coolite.com/)
License: MIT
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Files: src/calibre/ebooks/lrf/fonts/liberation/*
Copyright: Copyright (C) 2007, Red Hat, Inc. All rights reserved.
License: Other
Copyright (C) 2007, Red Hat, Inc. All rights reserved.
LIBERATION is a trademark of Red Hat, Inc.
This agreement governs the use of the Software and any updates to the Software,
regardless of the delivery mechanism. Subject to the following terms, Red Hat, Inc.
("Red Hat") grants to the user ("Client") a license to this work pursuant to
the GNU General Public License v.2 with the exceptions set forth below and such
other terms as our set forth in this End User License Agreement.
1. The Software and License Exception. LIBERATION font software (the "Software")
consists of TrueType-OpenType formatted font software for rendering LIBERATION
typefaces in sans serif, serif, and monospaced character styles. You are licensed
to use, modify, copy, and distribute the Software pursuant to the GNU General
Public License v.2 with the following exceptions:
(a) As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not
wish to do so, delete this exception statement from your version.
(b) As a further exception, any distribution of the object code of the Software
in a physical product must provide you the right to access and modify the
source code for the Software and to reinstall that modified version of the
Software in object code form on the same physical product on which you
received it.
2. Intellectual Property Rights. The Software and each of its components, including
the source code, documentation, appearance, structure and organization are owned
by Red Hat and others and are protected under copyright and other laws. Title to
the Software and any component, or to any copy, modification, or merged portion
shall remain with the aforementioned, subject to the applicable license.
The "LIBERATION" trademark is a trademark of Red Hat, Inc. in the U.S. and other
countries. This agreement does not permit Client to distribute modified versions
of the Software using Red Hat's trademarks. If Client makes a redistribution of
a modified version of the Software, then Client must modify the files names to
remove any reference to the Red Hat trademarks and must not use the Red Hat
trademarks in any way to reference or promote the modified Software.
3. Limited Warranty. To the maximum extent permitted under applicable law, the
Software is provided and licensed "as is" without warranty of any kind,
expressed or implied, including the implied warranties of merchantability,
non-infringement or fitness for a particular purpose. Red Hat does not warrant
that the functions contained in the Software will meet Client's requirements or
that the operation of the Software will be entirely error free or appear precisely
as described in the accompanying documentation.
4. Limitation of Remedies and Liability. To the maximum extent permitted by applicable
law, Red Hat or any Red Hat authorized dealer will not be liable to Client for any
incidental or consequential damages, including lost profits or lost savings arising
out of the use or inability to use the Software, even if Red Hat or such dealer has
been advised of the possibility of such damages.
5. General. If any provision of this agreement is held to be unenforceable, that shall
not affect the enforceability of the remaining provisions. This agreement shall be
governed by the laws of the State of North Carolina and of the United States, without
regard to any conflict of laws provisions, except that the United Nations Convention
on the International Sale of Goods shall not apply.
Files: installer/cx_Freeze/*
Copyright: Copyright © 2007-2008, Colt Engineering, Edmonton, Alberta, Canada.
Copyright: Copyright © 2001-2006, Computronix (Canada) Ltd., Edmonton, Alberta, Canada.
License: other
All rights reserved.
NOTE: this license is derived from the Python Software Foundation License
which can be found at http://www.python.org/psf/license
License for cx_Freeze 4.0.1
---------------------------
1. This LICENSE AGREEMENT is between the copyright holders and the Individual
or Organization ("Licensee") accessing and otherwise using cx_Freeze
software in source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, the
copyright holders hereby grant Licensee a nonexclusive, royalty-free,
world-wide license to reproduce, analyze, test, perform and/or display
publicly, prepare derivative works, distribute, and otherwise use cx_Freeze
alone or in any derivative version, provided, however, that this License
Agreement and this notice of copyright are retained in cx_Freeze alone or in
any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates cx_Freeze or any part thereof, and wants to make the derivative
work available to others as provided herein, then Licensee hereby agrees to
include in any such work a brief summary of the changes made to cx_Freeze.
4. The copyright holders are making cx_Freeze available to Licensee on an
"AS IS" basis. THE COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, THE COPYRIGHT
HOLDERS MAKE NO AND DISCLAIM ANY REPRESENTATION OR WARRANTY OF
MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
CX_FREEZE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. THE COPYRIGHT HOLDERS SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF
CX_FREEZE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING CX_FREEZE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach
of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between the copyright holders and
Licensee. This License Agreement does not grant permission to use
copyright holder's trademarks or trade name in a trademark sense to endorse
or promote products or services of Licensee, or any third party.
8. By copying, installing or otherwise using cx_Freeze, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
Computronix® is a registered trademark of Computronix (Canada) Ltd.

View File

@ -47,8 +47,8 @@ class DeviceScanner(object):
rev = ('rev_%4.4x'%c).replace('a', ':')
if rev in device_id:
return True
return False
return False
def test_bcd(self, bcdDevice, bcd):
if bcd is None or len(bcd) == 0:
return True
@ -56,19 +56,20 @@ class DeviceScanner(object):
if c == bcdDevice:
return True
return False
def is_device_connected(self, device):
vendor_ids = device.VENDOR_ID if hasattr(device.VENDOR_ID, '__len__') else [device.VENDOR_ID]
product_ids = device.PRODUCT_ID if hasattr(device.PRODUCT_ID, '__len__') else [device.PRODUCT_ID]
if iswindows:
for vendor_id, product_id in zip(vendor_ids, product_ids):
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
vidd, pidd = 'vid_%i'%vendor_id, 'pid_%i'%product_id
for device_id in self.devices:
if (vid in device_id or vidd in device_id) and (pid in device_id or pidd in device_id):
if self.test_bcd_windows(device_id, getattr(device, 'BCD', None)):
if device.can_handle(device_id):
return True
for vendor_id in vendor_ids:
for product_id in product_ids:
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
vidd, pidd = 'vid_%i'%vendor_id, 'pid_%i'%product_id
for device_id in self.devices:
if (vid in device_id or vidd in device_id) and (pid in device_id or pidd in device_id):
if self.test_bcd_windows(device_id, getattr(device, 'BCD', None)):
if device.can_handle(device_id):
return True
else:
for vendor, product, bcdDevice in self.devices:
if vendor in vendor_ids and product in product_ids:

View File

@ -18,7 +18,7 @@ from xml.dom import SyntaxErr as CSSSyntaxError
import cssutils
from cssutils.css import CSSStyleRule, CSSPageRule, CSSStyleDeclaration, \
CSSValueList, cssproperties
from cssutils.profiles import profiles as cssprofiles
from cssutils import profile as cssprofiles
from lxml import etree
from lxml.cssselect import css_to_xpath, ExpressionError, SelectorSyntaxError
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

View File

@ -20,7 +20,7 @@ DEPENDENCIES = [
('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'),
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
('poppler', '0.10.5', 'poppler', 'poppler', 'poppler', 'poppler'),
('pdftk', '1.12', 'pdftk', 'pdftk', 'pdftk', 'pdftk'),
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
]

View File

@ -49,7 +49,7 @@
</p>
<p>
${app} is available in the software repositories of the following
linux distributions:
supported linux distributions:
<table id="install_info">
<col width="150" /><col width="*" />
<tr>

View File

@ -42,7 +42,7 @@ recipe_modules = ['recipe_' + r for r in (
'moneynews', 'der_standard', 'diepresse', 'nzz_ger', 'hna',
'seattle_times', 'scott_hanselman', 'coding_horror', 'twitchfilms',
'stackoverflow', 'telepolis_artikel', 'zaobao', 'usnews',
'straitstimes',
'straitstimes', 'index_hu', 'pcworld_hu', 'hrt', 'rts',
)]
import re, imp, inspect, time, os

View File

@ -16,12 +16,14 @@ class Blic(BasicNewsRecipe):
description = 'Blic.co.yu online verzija najtiraznije novine u Srbiji donosi najnovije vesti iz Srbije i sveta, komentare, politicke analize, poslovne i ekonomske vesti, vesti iz regiona, intervjue, informacije iz kulture, reportaze, pokriva sve sportske dogadjaje, detaljan tv program, nagradne igre, zabavu, fenomenalni Blic strip, dnevni horoskop, arhivu svih dogadjaja'
publisher = 'RINGIER d.o.o.'
category = 'news, politics, Serbia'
delay = 1
oldest_article = 2
max_articles_per_feed = 100
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
language = _('Serbian')
lang = 'sr-Latn-RS'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif} '
html2lrf_options = [
@ -45,26 +47,14 @@ class Blic(BasicNewsRecipe):
start_url, question, rest_url = url.partition('?')
return u'http://www.blic.rs/_print.php?' + rest_url
def cleanup_image_tags(self,soup):
for item in soup.findAll('img'):
for attrib in ['height','width','border','align']:
if item.has_key(attrib):
del item[attrib]
oldParent = item.parent
myIndex = oldParent.contents.index(item)
item.extract()
divtag = Tag(soup,'div')
brtag = Tag(soup,'br')
oldParent.insert(myIndex,divtag)
divtag.append(item)
divtag.append(brtag)
return soup
def preprocess_html(self, soup):
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-RS"/>'
soup.head.insert(0,mtag)
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
soup.head.insert(0,mlang)
for item in soup.findAll(style=True):
del item['style']
return self.cleanup_image_tags(soup)
return self.adeify_images(soup)
def get_article_url(self, article):
raw = article.get('link', None)
return raw.replace('.co.yu','.rs')

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
'''
www.hrt.hr
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class HRT(BasicNewsRecipe):
title = 'HRT: Vesti'
__author__ = 'Darko Miletic'
description = 'News from Croatia'
publisher = 'HRT'
category = 'news, politics, Croatia, HRT'
no_stylesheets = True
encoding = 'utf-8'
use_embedded_content = False
language = _("Croatian")
lang = 'hr-HR'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: serif1, serif}'
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [dict(name='div', attrs={'class':'bigVijest'})]
remove_tags = [dict(name=['object','link','embed'])]
remove_tags_after = dict(name='div', attrs={'class':'nsAuthor'})
feeds = [
(u'Vijesti' , u'http://www.hrt.hr/?id=316&type=100&rss=vijesti' )
,(u'Sport' , u'http://www.hrt.hr/?id=316&type=100&rss=sport' )
,(u'Zabava' , u'http://www.hrt.hr/?id=316&type=100&rss=zabava' )
,(u'Filmovi i serije' , u'http://www.hrt.hr/?id=316&type=100&rss=filmovi' )
,(u'Dokumentarni program', u'http://www.hrt.hr/?id=316&type=100&rss=dokumentarci')
,(u'Glazba' , u'http://www.hrt.hr/?id=316&type=100&rss=glazba' )
,(u'Kultura' , u'http://www.hrt.hr/?id=316&type=100&rss=kultura' )
,(u'Mladi' , u'http://www.hrt.hr/?id=316&type=100&rss=mladi' )
,(u'Manjine' , u'http://www.hrt.hr/?id=316&type=100&rss=manjine' )
,(u'Radio' , u'http://www.hrt.hr/?id=316&type=100&rss=radio' )
]
def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
for item in soup.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -0,0 +1,20 @@
from calibre.web.feeds.news import BasicNewsRecipe
class Index(BasicNewsRecipe):
title = u'INDEX.HU'
oldest_article = 3
max_articles_per_feed = 50
language = _('Hungarian')
__author__ = 'Ezmegaz'
feeds = [(u'ALL', u'http://index.hu/24ora/rss/'),
(u'BELF\xd6LD', u'http://index.hu/belfold/rss/default/'),
(u'K\xdcLF\xd6LD', u'http://index.hu/kulfold/rss/default/'),
(u'BULV\xc1R', u'http://index.hu/bulvar/rss/default/'),
(u'GAZDAS\xc1G', u'http://index.hu/gazdasag/rss/default/'),
(u'TECH', u'http://index.hu/tech/rss/main/'),
(u'KULT\xdaRA', u'http://index.hu/kultur/rss/main/'),
(u'TUDOM\xc1NY', u'http://index.hu/tudomany/rss/main/'),
(u'V\xc9LEM\xc9NY', u'http://index.hu/velemeny/rss/default/')]

View File

@ -8,12 +8,13 @@ nin.co.rs
import re, urllib
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class Nin(BasicNewsRecipe):
title = 'NIN online'
__author__ = 'Darko Miletic'
description = 'Nedeljne informativne novine'
publisher = 'NIN'
publisher = 'NIN D.O.O.'
category = 'news, politics, Serbia'
no_stylesheets = True
oldest_article = 15
@ -28,9 +29,9 @@ class Nin(BasicNewsRecipe):
remove_javascript = True
use_embedded_content = False
language = _('Serbian')
lang = 'sr-RS'
lang = 'sr-Latn-RS'
direction = 'ltr'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif} .artTitle{font-size: x-large; font-weight: bold} .columnhead{font-size: small; font-weight: bold}'
html2lrf_options = [
'--comment' , description
@ -70,9 +71,10 @@ class Nin(BasicNewsRecipe):
def preprocess_html(self, soup):
soup.html['lang'] = self.lang
soup.html['dir' ] = self.direction
mtag = '<meta http-equiv="Content-Language" content="' + self.lang + '"/>'
mtag += '\n<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '"/>'
soup.head.insert(0,mtag)
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from calibre.web.feeds.news import BasicNewsRecipe
class Index(BasicNewsRecipe):
title = u'PCWORLD.HU'
oldest_article = 3
max_articles_per_feed = 50
language = _('Hungarian')
__author__ = 'Ezmegaz'
feeds = [(u'H\xedrek', u'http://pcworld.hu/rss/rss.xml'), (u'Hardver h\xedrek', u'http://www.pcworld.hu/rss/rss_hardverhirek.xml'), (u'Szoftver h\xedrek', u'http://www.pcworld.hu/rss/rss_szoftverhirek.xml'), (u'Hardver cikkek', u'http://www.pcworld.hu/rss/rss_hardvercikkek.xml'), (u'Szoftver cikkek', u'http://www.pcworld.hu/rss/rss_szoftvercikkek.xml'), (u'Mobil h\xedrek', u'http://www.pcworld.hu/rss/rss_mobil.xml'), (u'\xdczleti h\xedrek', u'http://www.pcworld.hu/rss/rss_uzlet.xml'), (u'Let\xf6lt\xe9sek', u'http://www.pcworld.hu/rss/rss_letoltes.xml'), (u'PC World TV', u'http://tv.pcworld.hu/rss/rss_hun_pcw.xml'), (u'Tudta-e...?', u'http://pcworld.hu/rss/rss_tudtae.xml')]

View File

@ -10,6 +10,7 @@ pobjeda.co.me
import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class Pobjeda(BasicNewsRecipe):
title = 'Pobjeda Online'
@ -22,12 +23,13 @@ class Pobjeda(BasicNewsRecipe):
encoding = 'utf8'
remove_javascript = True
use_embedded_content = False
language = _('Serbian')
lang = 'sr-Latn-Me'
INDEX = u'http://www.pobjeda.co.me'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: serif1, serif}'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: serif1, serif}'
html2lrf_options = [
'--comment', description
, '--base-font-size', '10'
, '--category', category
, '--publisher', publisher
]
@ -59,11 +61,13 @@ class Pobjeda(BasicNewsRecipe):
]
def preprocess_html(self, soup):
soup.html['xml:lang'] = 'sr-Latn-ME'
soup.html['lang'] = 'sr-Latn-ME'
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-ME"/>'
soup.head.insert(0,mtag)
return soup
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
return self.adeify_images(soup)
def get_cover_url(self):
cover_url = None

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
'''
www.rts.rs
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class RTS(BasicNewsRecipe):
title = 'RTS: Vesti'
__author__ = 'Darko Miletic'
description = 'News from Serbia'
publisher = 'RTS'
category = 'news, politics, Serbia, RTS'
no_stylesheets = True
encoding = 'utf-8'
use_embedded_content = True
language = _("Serbian")
lang = 'sr-Latn-RS'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: serif1, serif}'
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
feeds = [
(u'Vesti' , u'http://www.rts.rs/page/stories/sr/rss.html' )
,(u'Srbija' , u'http://www.rts.rs/page/stories/sr/rss/9/Srbija.html' )
,(u'Region' , u'http://www.rts.rs/page/stories/sr/rss/11/Region.html' )
,(u'Svet' , u'http://www.rts.rs/page/stories/sr/rss/10/Svet.html' )
,(u'Hronika' , u'http://www.rts.rs/page/stories/sr/rss/135/Hronika.html' )
,(u'Drustvo' , u'http://www.rts.rs/page/stories/sr/rss/125/Dru%C5%A1tvo.html')
,(u'Ekonomija' , u'http://www.rts.rs/page/stories/sr/rss/13/Ekonomija.html' )
,(u'Nauka' , u'http://www.rts.rs/page/stories/sr/rss/14/Nauka.html' )
,(u'Kultura' , u'http://www.rts.rs/page/stories/sr/rss/16/Kultura.html' )
,(u'Zanimljivosti' , u'http://www.rts.rs/page/stories/sr/rss/15/Zanimljivosti.html')
,(u'Sport' , u'http://www.rts.rs/page/sport/sr/rss.html' )
]
def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
return self.adeify_images(soup)

View File

@ -1,39 +1,48 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
'''
sptimes.ru
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class PetersburgTimes(BasicNewsRecipe):
title = u'The St. Petersburg Times'
__author__ = 'Darko Miletic'
description = 'News from Russia'
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
language = _('English')
INDEX = 'http://www.sptimes.ru'
def parse_index(self):
articles = []
soup = self.index_to_soup(self.INDEX)
for item in soup.findAll('a', attrs={'class':'story_link_o'}):
if item.has_key('href'):
url = self.INDEX + item['href'].replace('action_id=2','action_id=100')
title = self.tag_to_string(item)
c_date = strftime('%A, %d %B, %Y')
description = ''
articles.append({
'title':title,
'date':c_date,
'url':url,
'description':description
})
return [(soup.head.title.string, articles)]
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
'''
sptimes.ru
'''
from calibre.web.feeds.news import BasicNewsRecipe
class PetersburgTimes(BasicNewsRecipe):
title = 'The St. Petersburg Times'
__author__ = 'Darko Miletic'
description = 'News from Russia'
publisher = 'sptimes.ru'
category = 'news, politics, Russia'
max_articles_per_feed = 100
no_stylesheets = True
remove_javascript = True
encoding = 'cp1251'
use_embedded_content = False
language = _('English')
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
, '--ignore-tables'
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
remove_tags = [dict(name=['object','link','embed'])]
feeds = [(u'Headlines', u'http://sptimes.ru/headlines.php' )]
def preprocess_html(self, soup):
return self.adeify_images(soup)
def get_article_url(self, article):
raw = article.get('guid', None)
return raw
def print_version(self, url):
start_url, question, article_id = url.rpartition('/')
return u'http://www.sptimes.ru/index.php?action_id=100&story_id=' + article_id

View File

@ -9,6 +9,7 @@ vijesti.me
import re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class Vijesti(BasicNewsRecipe):
title = 'Vijesti'
@ -16,8 +17,8 @@ class Vijesti(BasicNewsRecipe):
description = 'News from Montenegro'
publisher = 'Daily Press Vijesti'
category = 'news, politics, Montenegro'
oldest_article = 1
max_articles_per_feed = 100
oldest_article = 2
max_articles_per_feed = 150
no_stylesheets = True
remove_javascript = True
encoding = 'cp1250'
@ -25,7 +26,8 @@ class Vijesti(BasicNewsRecipe):
remove_javascript = True
use_embedded_content = False
language = _('Serbian')
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
lang ='sr-Latn-Me'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: sans1, sans-serif}'
html2lrf_options = [
'--comment', description
@ -44,12 +46,15 @@ class Vijesti(BasicNewsRecipe):
feeds = [(u'Sve vijesti', u'http://www.vijesti.me/rss.php' )]
def preprocess_html(self, soup):
soup.html['xml:lang'] = 'sr-Latn-ME'
soup.html['lang'] = 'sr-Latn-ME'
mtag = '<meta http-equiv="Content-Language" content="sr-Latn-ME"/>'
soup.head.insert(0,mtag)
for item in soup.findAll('img'):
if item.has_key('align'):
del item['align']
item.insert(0,'<br /><br />')
return soup
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
return self.adeify_images(soup)
def get_article_url(self, article):
raw = article.get('link', None)
return raw.replace('.cg.yu','.me')

View File

@ -9,6 +9,7 @@ vreme.com
import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
class Vreme(BasicNewsRecipe):
title = 'Vreme'
@ -27,7 +28,7 @@ class Vreme(BasicNewsRecipe):
language = _('Serbian')
lang = 'sr-Latn-RS'
direction = 'ltr'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{text-align: justify; font-family: serif1, serif} .article_description{font-family: serif1, serif}'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} body{font-family: serif1, serif} .article_description{font-family: serif1, serif} .heading1{font-size: x-large; font-weight: bold} .heading2{font-size: large; font-weight: bold} .toc-heading{font-size: small}'
html2lrf_options = [
'--comment' , description
@ -89,9 +90,10 @@ class Vreme(BasicNewsRecipe):
del item['size']
soup.html['lang'] = self.lang
soup.html['dir' ] = self.direction
mtag = '<meta http-equiv="Content-Language" content="' + self.lang + '"/>'
mtag += '\n<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '"/>'
soup.head.insert(0,mtag)
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=UTF-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
return soup
def get_cover_url(self):

View File

@ -70,11 +70,11 @@ Usage may be::
__all__ = ['css', 'stylesheets', 'CSSParser', 'CSSSerializer']
__docformat__ = 'restructuredtext'
__author__ = 'Christof Hoeke with contributions by Walter Doerwald'
__date__ = '$LastChangedDate:: 2009-02-16 12:05:02 -0800 #$:'
__date__ = '$LastChangedDate:: 2009-05-09 13:59:54 -0700 #$:'
VERSION = '0.9.6a1'
VERSION = '0.9.6a5'
__version__ = '%s $Id: __init__.py 1669 2009-02-16 20:05:02Z cthedot $' % VERSION
__version__ = '%s $Id: __init__.py 1747 2009-05-09 20:59:54Z cthedot $' % VERSION
import codec
import xml.dom
@ -92,6 +92,9 @@ from parse import CSSParser
from serialize import CSSSerializer
ser = CSSSerializer()
from profiles import Profiles
profile = Profiles(log=log)
# used by Selector defining namespace prefix '*'
_ANYNS = -1

View File

@ -1,7 +1,7 @@
"""CSSMediaRule implements DOM Level 2 CSS CSSMediaRule."""
__all__ = ['CSSMediaRule']
__docformat__ = 'restructuredtext'
__version__ = '$Id: cssmediarule.py 1641 2009-01-13 21:05:37Z cthedot $'
__version__ = '$Id: cssmediarule.py 1743 2009-05-09 20:33:15Z cthedot $'
import cssrule
import cssutils
@ -131,8 +131,15 @@ class CSSMediaRule(cssrule.CSSRule):
mediaendonly=True,
separateEnd=True)
nonetoken = self._nexttoken(tokenizer, None)
if (u'}' != self._tokenvalue(braceOrEOF) and
'EOF' != self._type(braceOrEOF)):
if 'EOF' == self._type(braceOrEOF):
# HACK!!!
# TODO: Not complete, add EOF to rule and } to @media
cssrulestokens.append(braceOrEOF)
braceOrEOF = ('CHAR', '}', 0, 0)
self._log.debug(u'CSSMediaRule: Incomplete, adding "}".',
token=braceOrEOF, neverraise=True)
if u'}' != self._tokenvalue(braceOrEOF):
self._log.error(u'CSSMediaRule: No "}" found.',
token=braceOrEOF)
elif nonetoken:

View File

@ -51,7 +51,7 @@ TODO:
"""
__all__ = ['CSSStyleDeclaration', 'Property']
__docformat__ = 'restructuredtext'
__version__ = '$Id: cssstyledeclaration.py 1658 2009-02-07 18:24:40Z cthedot $'
__version__ = '$Id: cssstyledeclaration.py 1710 2009-04-18 15:46:20Z cthedot $'
from cssproperties import CSS2Properties
from property import Property
@ -613,7 +613,7 @@ class CSSStyleDeclaration(CSS2Properties, cssutils.util.Base2):
except IndexError:
return u''
length = property(lambda self: len(self.__nnames()),
length = property(lambda self: len(list(self.__nnames())),
doc="(DOM) The number of distinct properties that have been explicitly "
"in this declaration block. The range of valid indices is 0 to "
"length-1 inclusive. These are properties with a different ``name`` "

View File

@ -7,10 +7,9 @@
"""
__all__ = ['CSSValue', 'CSSPrimitiveValue', 'CSSValueList', 'RGBColor']
__docformat__ = 'restructuredtext'
__version__ = '$Id: cssvalue.py 1638 2009-01-13 20:39:33Z cthedot $'
__version__ = '$Id: cssvalue.py 1684 2009-03-01 18:26:21Z cthedot $'
from cssutils.prodparser import *
from cssutils.profiles import profiles
import cssutils
import cssutils.helper
import re
@ -121,7 +120,8 @@ class CSSValue(cssutils.util._NewBase):
# special case IE only expression
Prod(name='expression',
match=lambda t, v: t == self._prods.FUNCTION and
cssutils.helper.normalize(v) == 'expression(',
cssutils.helper.normalize(v) in (u'expression(',
u'alpha('),
nextSor=nextSor,
toSeq=lambda t, tokens: (ExpressionValue.name,
ExpressionValue(cssutils.helper.pushtoken(t,
@ -968,7 +968,8 @@ class RGBColor(CSSPrimitiveValue):
class ExpressionValue(CSSFunction):
"""Special IE only CSSFunction which may contain *anything*."""
"""Special IE only CSSFunction which may contain *anything*.
Used for expressions and ``alpha(opacity=100)`` currently"""
name = u'Expression (IE only)'
def _productiondefinition(self):

View File

@ -1,10 +1,9 @@
"""Property is a single CSS property in a CSSStyleDeclaration."""
__all__ = ['Property']
__docformat__ = 'restructuredtext'
__version__ = '$Id: property.py 1664 2009-02-07 22:47:09Z cthedot $'
__version__ = '$Id: property.py 1685 2009-03-01 18:26:48Z cthedot $'
from cssutils.helper import Deprecated
from cssutils.profiles import profiles
from cssvalue import CSSValue
import cssutils
import xml.dom
@ -67,6 +66,7 @@ class Property(cssutils.util.Base):
self._mediaQuery = _mediaQuery
self._parent = _parent
self.__nametoken = None
self._name = u''
self._literalname = u''
if name:
@ -193,6 +193,7 @@ class Property(cssutils.util.Base):
# define a token for error logging
if isinstance(name, list):
token = name[0]
self.__nametoken = token
else:
token = None
@ -208,9 +209,9 @@ class Property(cssutils.util.Base):
self.seqs[0] = newseq
# # validate
if self._name not in profiles.knownnames:
if self._name not in cssutils.profile.knownNames:
# self.valid = False
self._log.warn(u'Property: Unknown Property.',
self._log.warn(u'Property: Unknown Property name.',
token=token, neverraise=True)
else:
pass
@ -354,7 +355,7 @@ class Property(cssutils.util.Base):
# validate priority
if self._priority not in (u'', u'important'):
self._log.error(u'Property: No CSS priority value: %r.' %
self._priority)
self._priority)
priority = property(lambda self: self._priority, _setPriority,
doc="Priority of this property.")
@ -362,42 +363,101 @@ class Property(cssutils.util.Base):
literalpriority = property(lambda self: self._literalpriority,
doc="Readonly literal (not normalized) priority of this property")
def validate(self, profile=None):
"""Validate value against `profile`.
def validate(self, profiles=None):
"""Validate value against `profiles`.
:param profile:
A profile name used for validating. If no `profile` is given
``Property.profiles
:param profiles:
A list of profile names used for validating. If no `profiles`
is given ``cssutils.profile.defaultProfiles`` is used
For each of the following cases a message is reported:
- INVALID (so the property is known but not valid)
``ERROR Property: Invalid value for "{PROFILE-1[/PROFILE-2...]"
property: ...``
- VALID but not in given profiles or defaultProfiles
``WARNING Property: Not valid for profile "{PROFILE-X}" but valid
"{PROFILE-Y}" property: ...``
- VALID in current profile
``DEBUG Found valid "{PROFILE-1[/PROFILE-2...]" property...``
- UNKNOWN property
``WARNING Unknown Property name...`` is issued
so for example::
cssutils.log.setLevel(logging.DEBUG)
parser = cssutils.CSSParser()
s = parser.parseString('''body {
unknown-property: x;
color: 4;
color: rgba(1,2,3,4);
color: red
}''')
# Log output:
WARNING Property: Unknown Property name. [2:9: unknown-property]
ERROR Property: Invalid value for "CSS Color Module Level 3/CSS Level 2.1" property: 4 [3:9: color]
DEBUG Property: Found valid "CSS Color Module Level 3" value: rgba(1, 2, 3, 4) [4:9: color]
DEBUG Property: Found valid "CSS Level 2.1" value: red [5:9: color]
and when setting an explicit default profile::
cssutils.profile.defaultProfiles = cssutils.profile.CSS_LEVEL_2
s = parser.parseString('''body {
unknown-property: x;
color: 4;
color: rgba(1,2,3,4);
color: red
}''')
# Log output:
WARNING Property: Unknown Property name. [2:9: unknown-property]
ERROR Property: Invalid value for "CSS Color Module Level 3/CSS Level 2.1" property: 4 [3:9: color]
WARNING Property: Not valid for profile "CSS Level 2.1" but valid "CSS Color Module Level 3" value: rgba(1, 2, 3, 4) [4:9: color]
DEBUG Property: Found valid "CSS Level 2.1" value: red [5:9: color]
"""
valid = False
if self.name and self.value:
if profile is None:
usedprofile = cssutils.profiles.defaultprofile
else:
usedprofile = profile
if self.name in profiles.knownnames:
valid, validprofiles = profiles.validateWithProfile(self.name,
self.value,
usedprofile)
if self.name in cssutils.profile.knownNames:
# add valid, matching, validprofiles...
valid, matching, validprofiles = \
cssutils.profile.validateWithProfile(self.name,
self.value,
profiles)
if not valid:
self._log.error(u'Property: Invalid value for "%s" property: %s: %s'
% (u'/'.join(validprofiles),
self.name,
self._log.error(u'Property: Invalid value for '
u'"%s" property: %s'
% (u'/'.join(validprofiles), self.value),
token=self.__nametoken,
neverraise=True)
# TODO: remove logic to profiles!
elif valid and not matching:#(profiles and profiles not in validprofiles):
if not profiles:
notvalidprofiles = u'/'.join(cssutils.profile.defaultProfiles)
else:
notvalidprofiles = profiles
self._log.warn(u'Property: Not valid for profile "%s" '
u'but valid "%s" value: %s '
% (notvalidprofiles, u'/'.join(validprofiles),
self.value),
token = self.__nametoken,
neverraise=True)
elif valid and (usedprofile and usedprofile not in validprofiles):
self._log.warn(u'Property: Not valid for profile "%s": %s: %s'
% (usedprofile, self.name, self.value),
neverraise=True)
valid = False
if valid:
self._log.info(u'Property: Found valid "%s" property: %s: %s'
% (u'/'.join(validprofiles),
self.name,
self.value),
elif valid:
self._log.debug(u'Property: Found valid "%s" value: %s'
% (u'/'.join(validprofiles), self.value),
token = self.__nametoken,
neverraise=True)
if self._priority not in (u'', u'important'):

View File

@ -7,7 +7,7 @@ TODO
"""
__all__ = ['Selector']
__docformat__ = 'restructuredtext'
__version__ = '$Id: selector.py 1638 2009-01-13 20:39:33Z cthedot $'
__version__ = '$Id: selector.py 1741 2009-05-09 18:20:20Z cthedot $'
from cssutils.util import _SimpleNamespaces
import cssutils
@ -701,6 +701,14 @@ class Selector(cssutils.util.Base2):
u'Selector: Unexpected negation.', token=token)
return expected
def _atkeyword(expected, seq, token, tokenizer=None):
"invalidates selector"
new['wellformed'] = False
self._log.error(
u'Selector: Unexpected ATKEYWORD.', token=token)
return expected
# expected: only|not or mediatype, mediatype, feature, and
newseq = self._tempSeq()
@ -727,7 +735,8 @@ class Selector(cssutils.util.Base2):
'INCLUDES': _attcombinator,
'S': _S,
'COMMENT': _COMMENT})
'COMMENT': _COMMENT,
'ATKEYWORD': _atkeyword})
wellformed = wellformed and new['wellformed']
# post condition

View File

@ -12,14 +12,14 @@ open issues
"""
__all__ = ['CSSProductions', 'MACROS', 'PRODUCTIONS']
__docformat__ = 'restructuredtext'
__version__ = '$Id: cssproductions.py 1537 2008-12-03 14:37:10Z cthedot $'
__version__ = '$Id: cssproductions.py 1738 2009-05-02 13:03:28Z cthedot $'
# a complete list of css3 macros
MACROS = {
'nonascii': r'[^\0-\177]',
'unicode': r'\\[0-9a-f]{1,6}(?:{nl}|{s})?',
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
'escape': r'{unicode}|\\[ -~\200-\777]',
#'escape': r'{unicode}|\\[ -~\200-\777]',
'escape': r'{unicode}|\\[^\n\r\f0-9a-f]',
'nmstart': r'[_a-zA-Z]|{nonascii}|{escape}',
'nmchar': r'[-_a-zA-Z0-9]|{nonascii}|{escape}',
'string1': r'"([^\n\r\f\\"]|\\{nl}|{escape})*"',

View File

@ -16,7 +16,7 @@ log
"""
__all__ = ['ErrorHandler']
__docformat__ = 'restructuredtext'
__version__ = '$Id: errorhandler.py 1560 2008-12-14 16:13:16Z cthedot $'
__version__ = '$Id: errorhandler.py 1728 2009-05-01 20:35:25Z cthedot $'
from helper import Deprecated
import logging
@ -27,7 +27,7 @@ class _ErrorHandler(object):
"""
handles all errors and log messages
"""
def __init__(self, log, defaultloglevel=logging.INFO,
def __init__(self, log, defaultloglevel=logging.INFO,
raiseExceptions=True):
"""
inits log if none given
@ -51,7 +51,7 @@ class _ErrorHandler(object):
hdlr.setFormatter(formatter)
self._log.addHandler(hdlr)
self._log.setLevel(defaultloglevel)
self.raiseExceptions = raiseExceptions
def __getattr__(self, name):
@ -86,12 +86,12 @@ class _ErrorHandler(object):
if error and self.raiseExceptions and not neverraise:
if isinstance(error, urllib2.HTTPError) or isinstance(error, urllib2.URLError):
raise
elif issubclass(error, xml.dom.DOMException):
elif issubclass(error, xml.dom.DOMException):
error.line = line
error.col = col
raise error(msg)
else:
raise error(msg)
# raise error(msg, line, col)
# else:
raise error(msg)
else:
self._logcall(msg)

View File

@ -68,6 +68,9 @@ def string(value):
u'\f', u'\\c ').replace(
u'"', u'\\"')
if value.endswith(u'\\'):
value = value[:-1] + u'\\\\'
return u'"%s"' % value
def stringvalue(string):
@ -77,7 +80,7 @@ def stringvalue(string):
``'a \'string'`` => ``a 'string``
"""
return string.replace('\\'+string[0], string[0])[1:-1]
return string.replace(u'\\'+string[0], string[0])[1:-1]
_match_forbidden_in_uri = re.compile(ur'''.*?[\(\)\s\;,'"]''', re.U).match
def uri(value):

View File

@ -1,41 +1,340 @@
"""CSS profiles.
css2 is based on cssvalues
contributed by Kevin D. Smith, thanks!
"cssvalues" is used as a property validator.
it is an importable object that contains a dictionary of compiled regular
expressions. The keys of this dictionary are all of the valid CSS property
names. The values are compiled regular expressions that can be used to
validate the values for that property. (Actually, the values are references
to the 'match' method of a compiled regular expression, so that they are
simply called like functions.)
"""CSS profiles.
Profiles is based on code by Kevin D. Smith, orginally used as cssvalues,
thanks!
"""
__all__ = ['profiles']
__all__ = ['Profiles']
__docformat__ = 'restructuredtext'
__version__ = '$Id: cssproperties.py 1116 2008-03-05 13:52:23Z cthedot $'
import cssutils
import re
class NoSuchProfileException(Exception):
"""Raised if no profile with given name is found"""
pass
class Profiles(object):
"""
All profiles used for validation. ``cssutils.profile`` is a
preset object of this class and used by all properties for validation.
Predefined profiles are (use
:meth:`~cssutils.profiles.Profiles.propertiesByProfile` to
get a list of defined properties):
:attr:`~cssutils.profiles.Profiles.CSS_LEVEL_2`
Properties defined by CSS2.1
:attr:`~cssutils.profiles.Profiles.CSS3_COLOR`
CSS 3 color properties
:attr:`~cssutils.profiles.Profiles.CSS3_BOX`
Currently overflow related properties only
:attr:`~cssutils.profiles.Profiles.CSS3_PAGED_MEDIA`
As defined at http://www.w3.org/TR/css3-page/ (at 090307)
Predefined macros are:
:attr:`~cssutils.profiles.Profiles._TOKEN_MACROS`
Macros containing the token values as defined to CSS2
:attr:`~cssutils.profiles.Profiles._MACROS`
Additional general macros.
If you want to redefine any of these macros do this in your custom
macros.
"""
CSS_LEVEL_2 = 'CSS Level 2.1'
CSS3_COLOR = CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3'
CSS3_BOX = CSS_BOX_LEVEL_3 = 'CSS Box Module Level 3'
CSS3_PAGED_MEDIA = 'CSS3 Paged Media Module'
_TOKEN_MACROS = {
'ident': r'[-]?{nmstart}{nmchar}*',
'name': r'{nmchar}+',
'nmstart': r'[_a-z]|{nonascii}|{escape}',
'nonascii': r'[^\0-\177]',
'unicode': r'\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?',
'escape': r'{unicode}|\\[ -~\200-\777]',
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
'int': r'[-]?\d+',
'nmchar': r'[\w-]|{nonascii}|{escape}',
'num': r'[-]?\d+|[-]?\d*\.\d+',
'number': r'{num}',
'string': r'{string1}|{string2}',
'string1': r'"(\\\"|[^\"])*"',
'uri': r'url\({w}({string}|(\\\)|[^\)])+){w}\)',
'string2': r"'(\\\'|[^\'])*'",
'nl': r'\n|\r\n|\r|\f',
'w': r'\s*',
}
_MACROS = {
'hexcolor': r'#[0-9a-f]{3}|#[0-9a-f]{6}',
'rgbcolor': r'rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)',
'namedcolor': r'(transparent|orange|maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray)',
'uicolor': r'(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)',
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{uicolor}',
#'color': r'(maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray|ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)|#[0-9a-f]{3}|#[0-9a-f]{6}|rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)',
'integer': r'{int}',
'length': r'0|{num}(em|ex|px|in|cm|mm|pt|pc)',
'angle': r'0|{num}(deg|grad|rad)',
'time': r'0|{num}m?s',
'frequency': r'0|{num}k?Hz',
'percentage': r'{num}%',
}
def __init__(self, log=None):
"""A few known profiles are predefined."""
self._log = log
self._profileNames = [] # to keep order, REFACTOR!
self._profiles = {}
self._defaultProfiles = None
self.addProfile(self.CSS_LEVEL_2,
properties[self.CSS_LEVEL_2],
macros[self.CSS_LEVEL_2])
self.addProfile(self.CSS3_BOX,
properties[self.CSS3_BOX],
macros[self.CSS3_BOX])
self.addProfile(self.CSS3_COLOR,
properties[self.CSS3_COLOR],
macros[self.CSS3_COLOR])
self.addProfile(self.CSS3_PAGED_MEDIA,
properties[self.CSS3_PAGED_MEDIA],
macros[self.CSS3_PAGED_MEDIA])
self.__update_knownNames()
def _expand_macros(self, dictionary, macros):
"""Expand macros in token dictionary"""
def macro_value(m):
return '(?:%s)' % macros[m.groupdict()['macro']]
for key, value in dictionary.items():
if not hasattr(value, '__call__'):
while re.search(r'{[a-z][a-z0-9-]*}', value):
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
macro_value, value)
dictionary[key] = value
return dictionary
def _compile_regexes(self, dictionary):
"""Compile all regular expressions into callable objects"""
for key, value in dictionary.items():
if not hasattr(value, '__call__'):
value = re.compile('^(?:%s)$' % value, re.I).match
dictionary[key] = value
return dictionary
def __update_knownNames(self):
self._knownNames = []
for properties in self._profiles.values():
self._knownNames.extend(properties.keys())
def _getDefaultProfiles(self):
"If not explicitly set same as Profiles.profiles but in reverse order."
if not self._defaultProfiles:
return self.profiles#list(reversed(self.profiles))
else:
return self._defaultProfiles
def _setDefaultProfiles(self, profiles):
"profiles may be a single or a list of profile names"
if isinstance(profiles, basestring):
self._defaultProfiles = (profiles,)
else:
self._defaultProfiles = profiles
defaultProfiles = property(_getDefaultProfiles,
_setDefaultProfiles,
doc=u"Names of profiles to use for validation."
u"To use e.g. the CSS2 profile set "
u"``cssutils.profile.defaultProfiles = "
u"cssutils.profile.CSS_LEVEL_2``")
profiles = property(lambda self: self._profileNames,
doc=u'Names of all profiles in order as defined.')
knownNames = property(lambda self: self._knownNames,
doc="All known property names of all profiles.")
def addProfile(self, profile, properties, macros=None):
"""Add a new profile with name `profile` (e.g. 'CSS level 2')
and the given `properties`.
:param profile:
the new `profile`'s name
:param properties:
a dictionary of ``{ property-name: propery-value }`` items where
property-value is a regex which may use macros defined in given
``macros`` or the standard macros Profiles.tokens and
Profiles.generalvalues.
``propery-value`` may also be a function which takes a single
argument which is the value to validate and which should return
True or False.
Any exceptions which may be raised during this custom validation
are reported or raised as all other cssutils exceptions depending
on cssutils.log.raiseExceptions which e.g during parsing normally
is False so the exceptions would be logged only.
:param macros:
may be used in the given properties definitions. There are some
predefined basic macros which may always be used in
:attr:`Profiles._TOKEN_MACROS` and :attr:`Profiles._MACROS`.
"""
if not macros:
macros = {}
m = Profiles._TOKEN_MACROS.copy()
m.update(Profiles._MACROS)
m.update(macros)
properties = self._expand_macros(properties, m)
self._profileNames.append(profile)
self._profiles[profile] = self._compile_regexes(properties)
self.__update_knownNames()
def removeProfile(self, profile=None, all=False):
"""Remove `profile` or remove `all` profiles.
:param profile:
profile name to remove
:param all:
if ``True`` removes all profiles to start with a clean state
:exceptions:
- :exc:`cssutils.profiles.NoSuchProfileException`:
If given `profile` cannot be found.
"""
if all:
self._profiles.clear()
del self._profileNames[:]
else:
try:
del self._profiles[profile]
del self._profileNames[self._profileNames.index(profile)]
except KeyError:
raise NoSuchProfileException(u'No profile %r.' % profile)
self.__update_knownNames()
def propertiesByProfile(self, profiles=None):
"""Generator: Yield property names, if no `profiles` is given all
profile's properties are used.
:param profiles:
a single profile name or a list of names.
"""
if not profiles:
profiles = self.profiles
elif isinstance(profiles, basestring):
profiles = (profiles, )
try:
for profile in sorted(profiles):
for name in sorted(self._profiles[profile].keys()):
yield name
except KeyError, e:
raise NoSuchProfileException(e)
def validate(self, name, value):
"""Check if `value` is valid for given property `name` using **any**
profile.
:param name:
a property name
:param value:
a CSS value (string)
:returns:
if the `value` is valid for the given property `name` in any
profile
"""
for profile in self.profiles:
if name in self._profiles[profile]:
try:
# custom validation errors are caught
r = bool(self._profiles[profile][name](value))
except Exception, e:
self._log.error(e, error=Exception)
return False
if r:
return r
return False
def validateWithProfile(self, name, value, profiles=None):
"""Check if `value` is valid for given property `name` returning
``(valid, profile)``.
:param name:
a property name
:param value:
a CSS value (string)
:param profiles:
internal parameter used by Property.validate only
:returns:
``valid, matching, profiles`` where ``valid`` is if the `value`
is valid for the given property `name` in any profile,
``matching==True`` if it is valid in the given `profiles`
and ``profiles`` the profile names for which the value is valid
(or ``[]`` if not valid at all)
Example::
>>> cssutils.profile.defaultProfiles = cssutils.profile.CSS_LEVEL_2
>>> print cssutils.profile.validateWithProfile('color', 'rgba(1,1,1,1)')
(True, False, Profiles.CSS3_COLOR)
"""
if name not in self.knownNames:
return False, False, []
else:
if not profiles:
profiles = self.defaultProfiles
elif isinstance(profiles, basestring):
profiles = (profiles, )
for profilename in profiles:
# check given profiles
if name in self._profiles[profilename]:
validate = self._profiles[profilename][name]
try:
if validate(value):
return True, True, [profilename]
except Exception, e:
self._log.error(e, error=Exception)
for profilename in (p for p in self._profileNames
if p not in profiles):
# check remaining profiles as well
if name in self._profiles[profilename]:
validate = self._profiles[profilename][name]
try:
if validate(value):
return True, False, [profilename]
except Exception, e:
self._log.error(e, error=Exception)
names = []
for profilename, properties in self._profiles.items():
# return profile to which name belongs
if name in properties.keys():
names.append(profilename)
names.sort()
return False, False, names
properties = {}
macros = {}
"""
Define some regular expression fragments that will be used as
macros within the CSS property value regular expressions.
"""
css2macros = {
macros[Profiles.CSS_LEVEL_2] = {
'border-style': 'none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset',
'border-color': '{color}',
'border-width': '{length}|thin|medium|thick',
'background-color': r'{color}|transparent|inherit',
'background-image': r'{uri}|none|inherit',
'background-position': r'({percentage}|{length})(\s*({percentage}|{length}))?|((top|center|bottom)\s*(left|center|right))|((left|center|right)\s*(top|center|bottom))|inherit',
#'background-position': r'({percentage}|{length})(\s*({percentage}|{length}))?|((top|center|bottom)\s*(left|center|right)?)|((left|center|right)\s*(top|center|bottom)?)|inherit',
'background-position': r'({percentage}|{length}|left|center|right)(\s*({percentage}|{length}|top|center|bottom))?|((top|center|bottom)\s*(left|center|right)?)|((left|center|right)\s*(top|center|bottom)?)|inherit',
'background-repeat': r'repeat|repeat-x|repeat-y|no-repeat|inherit',
'background-attachment': r'scroll|fixed|inherit',
'shape': r'rect\(({w}({length}|auto}){w},){3}{w}({length}|auto){w}\)',
'counter': r'counter\({w}{identifier}{w}(?:,{w}{list-style-type}{w})?\)',
'identifier': r'{ident}',
@ -72,7 +371,7 @@ css2macros = {
"""
Define the regular expressions for validation all CSS values
"""
properties['css2'] = {
properties[Profiles.CSS_LEVEL_2] = {
'azimuth': r'{angle}|(behind\s+)?(left-side|far-left|left|center-left|center|center-right|right|far-right|right-side)(\s+behind)?|behind|leftwards|rightwards|inherit',
'background-attachment': r'{background-attachment}',
'background-color': r'{background-color}',
@ -108,7 +407,7 @@ properties['css2'] = {
'clear': r'none|left|right|both|inherit',
'clip': r'{shape}|auto|inherit',
'color': r'{color}|inherit',
'content': r'normal|{content}(\s+{content})*|inherit',
'content': r'none|normal|{content}(\s+{content})*|inherit',
'counter-increment': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit',
'counter-reset': r'({identifier}(\s+{integer})?)(\s+({identifier}(\s+{integer})))*|none|inherit',
'cue-after': r'{uri}|none|inherit',
@ -191,288 +490,47 @@ properties['css2'] = {
'z-index': r'auto|{integer}|inherit',
}
# CSS Box Module Level 3
macros[Profiles.CSS3_BOX] = {
'overflow': macros[Profiles.CSS_LEVEL_2]['overflow']
}
properties[Profiles.CSS3_BOX] = {
'overflow': '{overflow}\s?{overflow}?|inherit',
'overflow-x': '{overflow}|inherit',
'overflow-y': '{overflow}|inherit'
}
# CSS Color Module Level 3
css3colormacros = {
macros[Profiles.CSS3_COLOR] = {
# orange and transparent in CSS 2.1
'namedcolor': r'(currentcolor|transparent|orange|black|green|silver|lime|gray|olive|white|yellow|maroon|navy|red|blue|purple|teal|fuchsia|aqua)',
'namedcolor': r'(currentcolor|transparent|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)',
# orange?
'rgbacolor': r'rgba\({w}{int}{w},{w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgba\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
'hslcolor': r'hsl\({w}{int}{w},{w}{num}%{w},{w}{num}%{w}\)|hsla\({w}{int}{w},{w}{num}%{w},{w}{num}%{w},{w}{num}{w}\)',
'x11color': r'aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen',
'uicolor': r'(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)',
}
properties['css3color'] = {
properties[Profiles.CSS3_COLOR] = {
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{rgbacolor}|{hslcolor}|inherit',
'opacity': r'{num}|inherit'
}
# CSS Box Module Level 3
properties['css3box'] = {
'overflow': '{overflow}\s?{overflow}?',
'overflow-x': '{overflow}',
'overflow-y': '{overflow}'
# CSS3 Paged Media
macros[Profiles.CSS3_PAGED_MEDIA] = {
'pagesize': 'a5|a4|a3|b5|b4|letter|legal|ledger',
'pagebreak': 'auto|always|avoid|left|right'
}
properties[Profiles.CSS3_PAGED_MEDIA] = {
'fit': 'fill|hidden|meet|slice',
'fit-position': r'auto|(({percentage}|{length})(\s*({percentage}|{length}))?|((top|center|bottom)\s*(left|center|right)?)|((left|center|right)\s*(top|center|bottom)?))',
'image-orientation': 'auto|{angle}',
'orphans': r'{integer}|inherit',
'page': 'auto|{ident}',
'page-break-before': '{pagebreak}|inherit',
'page-break-after': '{pagebreak}|inherit',
'page-break-inside': 'auto|avoid|inherit',
'size': '({length}{w}){1,2}|auto|{pagesize}{w}(?:portrait|landscape)',
'widows': r'{integer}|inherit'
}
class NoSuchProfileException(Exception):
"""Raised if no profile with given name is found"""
pass
class Profiles(object):
"""
All profiles used for validation. ``cssutils.profiles.profiles`` is a
preset object of this class and used by all properties for validation.
Predefined profiles are (use
:meth:`~cssutils.profiles.Profiles.propertiesByProfile` to
get a list of defined properties):
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_LEVEL_2`
Properties defined by CSS2.1
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_COLOR_LEVEL_3`
CSS 3 color properties
:attr:`~cssutils.profiles.Profiles.Profiles.CSS_BOX_LEVEL_3`
Currently overflow related properties only
"""
CSS_LEVEL_2 = 'CSS Level 2.1'
CSS_COLOR_LEVEL_3 = 'CSS Color Module Level 3'
CSS_BOX_LEVEL_3 = 'CSS Box Module Level 3'
basicmacros = {
'ident': r'[-]?{nmstart}{nmchar}*',
'name': r'{nmchar}+',
'nmstart': r'[_a-z]|{nonascii}|{escape}',
'nonascii': r'[^\0-\177]',
'unicode': r'\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?',
'escape': r'{unicode}|\\[ -~\200-\777]',
# 'escape': r'{unicode}|\\[ -~\200-\4177777]',
'int': r'[-]?\d+',
'nmchar': r'[\w-]|{nonascii}|{escape}',
'num': r'[-]?\d+|[-]?\d*\.\d+',
'number': r'{num}',
'string': r'{string1}|{string2}',
'string1': r'"(\\\"|[^\"])*"',
'uri': r'url\({w}({string}|(\\\)|[^\)])+){w}\)',
'string2': r"'(\\\'|[^\'])*'",
'nl': r'\n|\r\n|\r|\f',
'w': r'\s*',
}
generalmacros = {
'hexcolor': r'#[0-9a-f]{3}|#[0-9a-f]{6}',
'rgbcolor': r'rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)',
'namedcolor': r'(transparent|orange|maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray)',
'uicolor': r'(ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)',
'color': r'{namedcolor}|{hexcolor}|{rgbcolor}|{uicolor}',
#'color': r'(maroon|red|orange|yellow|olive|purple|fuchsia|white|lime|green|navy|blue|aqua|teal|black|silver|gray|ActiveBorder|ActiveCaption|AppWorkspace|Background|ButtonFace|ButtonHighlight|ButtonShadow|ButtonText|CaptionText|GrayText|Highlight|HighlightText|InactiveBorder|InactiveCaption|InactiveCaptionText|InfoBackground|InfoText|Menu|MenuText|Scrollbar|ThreeDDarkShadow|ThreeDFace|ThreeDHighlight|ThreeDLightShadow|ThreeDShadow|Window|WindowFrame|WindowText)|#[0-9a-f]{3}|#[0-9a-f]{6}|rgb\({w}{int}{w},{w}{int}{w},{w}{int}{w}\)|rgb\({w}{num}%{w},{w}{num}%{w},{w}{num}%{w}\)',
'integer': r'{int}',
'length': r'0|{num}(em|ex|px|in|cm|mm|pt|pc)',
'angle': r'0|{num}(deg|grad|rad)',
'time': r'0|{num}m?s',
'frequency': r'0|{num}k?Hz',
'percentage': r'{num}%',
}
def __init__(self):
"""A few known profiles are predefined."""
self._log = cssutils.log
self._profilenames = [] # to keep order, REFACTOR!
self._profiles = {}
self.addProfile(self.CSS_LEVEL_2, properties['css2'], css2macros)
self.addProfile(self.CSS_COLOR_LEVEL_3, properties['css3color'], css3colormacros)
self.addProfile(self.CSS_BOX_LEVEL_3, properties['css3box'])
self.__update_knownnames()
def _expand_macros(self, dictionary, macros):
"""Expand macros in token dictionary"""
def macro_value(m):
return '(?:%s)' % macros[m.groupdict()['macro']]
for key, value in dictionary.items():
if not hasattr(value, '__call__'):
while re.search(r'{[a-z][a-z0-9-]*}', value):
value = re.sub(r'{(?P<macro>[a-z][a-z0-9-]*)}',
macro_value, value)
dictionary[key] = value
return dictionary
def _compile_regexes(self, dictionary):
"""Compile all regular expressions into callable objects"""
for key, value in dictionary.items():
if not hasattr(value, '__call__'):
value = re.compile('^(?:%s)$' % value, re.I).match
dictionary[key] = value
return dictionary
def __update_knownnames(self):
self._knownnames = []
for properties in self._profiles.values():
self._knownnames.extend(properties.keys())
profiles = property(lambda self: sorted(self._profiles.keys()),
doc=u'Names of all profiles.')
knownnames = property(lambda self: self._knownnames,
doc="All known property names of all profiles.")
def addProfile(self, profile, properties, macros=None):
"""Add a new profile with name `profile` (e.g. 'CSS level 2')
and the given `properties`.
:param profile:
the new `profile`'s name
:param properties:
a dictionary of ``{ property-name: propery-value }`` items where
property-value is a regex which may use macros defined in given
``macros`` or the standard macros Profiles.tokens and
Profiles.generalvalues.
``propery-value`` may also be a function which takes a single
argument which is the value to validate and which should return
True or False.
Any exceptions which may be raised during this custom validation
are reported or raised as all other cssutils exceptions depending
on cssutils.log.raiseExceptions which e.g during parsing normally
is False so the exceptions would be logged only.
:param macros:
may be used in the given properties definitions. There are some
predefined basic macros which may always be used in
:attr:`Profiles.basicmacros` and :attr:`Profiles.generalmacros`.
"""
if not macros:
macros = {}
m = self.basicmacros
m.update(self.generalmacros)
m.update(macros)
properties = self._expand_macros(properties, m)
self._profilenames.append(profile)
self._profiles[profile] = self._compile_regexes(properties)
self.__update_knownnames()
def removeProfile(self, profile=None, all=False):
"""Remove `profile` or remove `all` profiles.
:param profile:
profile name to remove
:param all:
if ``True`` removes all profiles to start with a clean state
:exceptions:
- :exc:`cssutils.profiles.NoSuchProfileException`:
If given `profile` cannot be found.
"""
if all:
self._profiles.clear()
else:
try:
del self._profiles[profile]
except KeyError:
raise NoSuchProfileException(u'No profile %r.' % profile)
self.__update_knownnames()
def propertiesByProfile(self, profiles=None):
"""Generator: Yield property names, if no `profiles` is given all
profile's properties are used.
:param profiles:
a single profile name or a list of names.
"""
if not profiles:
profiles = self.profiles
elif isinstance(profiles, basestring):
profiles = (profiles, )
try:
for profile in sorted(profiles):
for name in sorted(self._profiles[profile].keys()):
yield name
except KeyError, e:
raise NoSuchProfileException(e)
def validate(self, name, value):
"""Check if `value` is valid for given property `name` using **any**
profile.
:param name:
a property name
:param value:
a CSS value (string)
:returns:
if the `value` is valid for the given property `name` in any
profile
"""
for profile in self.profiles:
if name in self._profiles[profile]:
try:
# custom validation errors are caught
r = bool(self._profiles[profile][name](value))
except Exception, e:
self._log.error(e, error=Exception)
return False
if r:
return r
return False
def validateWithProfile(self, name, value, profiles=None):
"""Check if `value` is valid for given property `name` returning
``(valid, profile)``.
:param name:
a property name
:param value:
a CSS value (string)
:returns:
``valid, profiles`` where ``valid`` is if the `value` is valid for
the given property `name` in any profile of given `profiles`
and ``profiles`` the profile names for which the value is valid
(or ``[]`` if not valid at all)
Example: You might expect a valid Profiles.CSS_LEVEL_2 value but
e.g. ``validateWithProfile('color', 'rgba(1,1,1,1)')`` returns
(True, Profiles.CSS_COLOR_LEVEL_3)
"""
if name not in self.knownnames:
return False, []
else:
if not profiles:
profiles = self._profilenames
elif isinstance(profiles, basestring):
profiles = (profiles, )
for profilename in profiles:
# check given profiles
if name in self._profiles[profilename]:
validate = self._profiles[profilename][name]
try:
if validate(value):
return True, [profilename]
except Exception, e:
self._log.error(e, error=Exception)
for profilename in (p for p in self._profilenames if p not in profiles):
# check remaining profiles as well
if name in self._profiles[profilename]:
validate = self._profiles[profilename][name]
try:
if validate(value):
return True, [profilename]
except Exception, e:
self._log.error(e, error=Exception)
names = []
for profilename, properties in self._profiles.items():
# return profile to which name belongs
if name in properties.keys():
names.append(profilename)
names.sort()
return False, names
# used by
profiles = Profiles()
# set for validation to e.g.``Profiles.CSS_LEVEL_2``
defaultprofile = None

View File

@ -3,7 +3,7 @@
"""cssutils serializer"""
__all__ = ['CSSSerializer', 'Preferences']
__docformat__ = 'restructuredtext'
__version__ = '$Id: serialize.py 1606 2009-01-03 20:32:17Z cthedot $'
__version__ = '$Id: serialize.py 1741 2009-05-09 18:20:20Z cthedot $'
import codecs
import cssutils
@ -58,6 +58,9 @@ class Preferences(object):
keepEmptyRules = False
defines if empty rules like e.g. ``a {}`` are kept in the resulting
serialized sheet
keepUnkownAtRules = True
defines if unknown @rules like e.g. ``@three-dee {}`` are kept in the
serialized sheet
keepUsedNamespaceRulesOnly = False
if True only namespace rules which are actually used are kept
@ -82,12 +85,10 @@ class Preferences(object):
spacer = u' '
general spacer, used e.g. by CSSUnknownRule
validOnly = False **DO NOT CHANGE YET**
if True only valid (currently Properties) are kept
validOnly = False
if True only valid (Properties) are output
A Property is valid if it is a known Property with a valid value.
Currently CSS 2.1 values as defined in cssproperties.py would be
valid.
"""
def __init__(self, **initials):
"""Always use named instead of positional parameters."""
@ -118,6 +119,7 @@ class Preferences(object):
self.keepAllProperties = True
self.keepComments = True
self.keepEmptyRules = False
self.keepUnkownAtRules = True
self.keepUsedNamespaceRulesOnly = False
self.lineNumbers = False
self.lineSeparator = u'\n'
@ -139,6 +141,7 @@ class Preferences(object):
self.indent = u''
self.keepComments = False
self.keepEmptyRules = False
self.keepUnkownAtRules = False
self.keepUsedNamespaceRulesOnly = True
self.lineNumbers = False
self.lineSeparator = u''
@ -563,7 +566,7 @@ class CSSSerializer(object):
anything until ";" or "{...}"
+ CSSComments
"""
if rule.wellformed:
if rule.wellformed and self.prefs.keepUnkownAtRules:
out = Out(self)
out.append(rule.atkeyword)
@ -741,10 +744,11 @@ class CSSSerializer(object):
out.append(separator)
elif isinstance(val, cssutils.css.Property):
# PropertySimilarNameList
out.append(val.cssText)
if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
out.append(u';')
out.append(separator)
if val.cssText:
out.append(val.cssText)
if not (self.prefs.omitLastSemicolon and i==len(seq)-1):
out.append(u';')
out.append(separator)
elif isinstance(val, cssutils.css.CSSUnknownRule):
# @rule
out.append(val.cssText)

View File

@ -5,7 +5,7 @@ A cssutils implementation, not defined in official DOM.
"""
__all__ = ['MediaQuery']
__docformat__ = 'restructuredtext'
__version__ = '$Id: mediaquery.py 1638 2009-01-13 20:39:33Z cthedot $'
__version__ = '$Id: mediaquery.py 1738 2009-05-02 13:03:28Z cthedot $'
import cssutils
import re
@ -21,8 +21,8 @@ class MediaQuery(cssutils.util.Base):
media_query: [[only | not]? <media_type> [ and <expression> ]*]
| <expression> [ and <expression> ]*
expression: ( <media_feature> [: <value>]? )
media_type: all | aural | braille | handheld | print |
projection | screen | tty | tv | embossed
media_type: all | braille | handheld | print |
projection | speech | screen | tty | tv | embossed
media_feature: width | min-width | max-width
| height | min-height | max-height
| device-width | min-device-width | max-device-width
@ -35,8 +35,8 @@ class MediaQuery(cssutils.util.Base):
| scan | grid
"""
MEDIA_TYPES = [u'all', u'aural', u'braille', u'embossed', u'handheld',
u'print', u'projection', u'screen', u'tty', u'tv']
MEDIA_TYPES = [u'all', u'braille', u'embossed', u'handheld',
u'print', u'projection', u'screen', u'speech', u'tty', u'tv']
# From the HTML spec (see MediaQuery):
# "[...] character that isn't a US ASCII letter [a-zA-Z] (Unicode

View File

@ -2,7 +2,7 @@
"""
__all__ = []
__docformat__ = 'restructuredtext'
__version__ = '$Id: util.py 1654 2009-02-03 20:16:20Z cthedot $'
__version__ = '$Id: util.py 1743 2009-05-09 20:33:15Z cthedot $'
from helper import normalize
from itertools import ifilter
@ -307,7 +307,6 @@ class Base(_BaseClass):
bracket == parant == 0) and typ in endtypes:
# mediaqueryendonly with STRING
break
if separateEnd:
# TODO: use this method as generator, then this makes sense
if resulttokens: