Index: abp/filters/renderer.py |
=================================================================== |
--- a/abp/filters/renderer.py |
+++ b/abp/filters/renderer.py |
@@ -8,56 +8,57 @@ |
# Adblock Plus is distributed in the hope that it will be useful, |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
# GNU General Public License for more details. |
# |
# You should have received a copy of the GNU General Public License |
# along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
+"""Combine filter list fragments to produce filter lists.""" |
+ |
from __future__ import unicode_literals |
import base64 |
import hashlib |
import itertools |
import logging |
import time |
from .parser import parse_filterlist, Comment, Metadata |
from .sources import NotFound |
-__all__ = ['render_filterlist', 'IncludeError', 'MissingHeader'] |
+__all__ = ['IncludeError', 'MissingHeader', 'render_filterlist'] |
_logger = logging.getLogger(__name__) |
class IncludeError(Exception): |
- """Error in processing include instruction. |
- |
- :param error: Description of the error. |
- :param stack: A list of the names of included files. |
- """ |
+ """Error in processing include instruction.""" |
def __init__(self, error, stack): |
stack_str = ' from '.join(map("'{}'".format, reversed(stack))) |
if stack_str: |
error = '{} when including {}'.format(error, stack_str) |
Exception.__init__(self, error) |
class MissingHeader(Exception): |
"""First line of the result is not a valid header.""" |
def _get_and_parse_fragment(name, sources, default_source, include_stack=[]): |
"""Retrieve and parse fragment. |
- :returns: a tuple `(lines_iterator, inherited_source)` where |
- `inherited_source` is the default source to use for included |
- fragments. |
+ Returns |
+ ------- |
+ tuple (iterator of str, Source) |
+ First part is the content of the fragment line by line; second part is |
+ the default source to be used for included fragments. |
+ |
""" |
if ':' in name: |
source_name, name_in_source = name.split(':', 1) |
try: |
source = sources[source_name] |
except KeyError: |
raise IncludeError("Unknown source: '{}'".format(source_name), |
include_stack) |
@@ -161,25 +162,40 @@ |
if first_line.type != 'header': |
raise MissingHeader('No header found at the beginning of the input.') |
return itertools.chain([first_line], rest) |
def render_filterlist(name, sources, top_source=None): |
"""Produce filter list from fragments. |
- :param name: Name of the top level fragment. |
- :param sources: A mapping of source names to sources for getting fragments. |
- :param top_source: Default source used for getting top fragment. |
- :returns: Iterable of of filter list lines (see `line_type` in parser.py). |
- :raises IncludeError: When an include error can't be processed. |
- :raises ParseError: When any of the fragments contain lines that can't |
- be parsed. |
- :raises MissingHeader: If the top level fragment doesn't start with a valid |
- header. |
+ Parameters |
+ ---------- |
+ name : str |
+ Name of the top level fragment. |
+ sources : dict of str -> Source |
+ Sources for loading included fragments. |
+ top_source : Source |
+ The source used to load the top level fragment. |
+ |
+ Returns |
+ ------- |
+ iterable of namedtuple (see `_line_type` in parser.py) |
+ Rendered filter list. |
+ |
+ Raises |
+ ------ |
+ IncludeError |
+ When an include error can't be processed. |
+ ParseError |
+ When any of the fragments contain lines that can't be parsed. |
+ MissingHeader |
+ If the top level fragment doesn't start with a valid header. This would |
+ lead to rendering an invalid filter list, so we immediately abort. |
+ |
""" |
_logger.info('Rendering: %s', name) |
lines, default_source = _get_and_parse_fragment(name, sources, top_source) |
lines = _process_includes(sources, default_source, [name], lines) |
for proc in [_process_timestamps, _insert_version, _remove_duplicates, |
_insert_checksum, _validate]: |
lines = proc(lines) |
return lines |