/usr/lib/python2.7/dist-packages/efilter/ext/lazy_repetition.py is in python-efilter 1.5-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | # EFILTER Forensic Query Language
#
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Implements IRepeated using a restartable generator.
"""
__author__ = "Adam Sindelar <adamsh@google.com>"
from efilter.protocols import counted
from efilter.protocols import ordered
from efilter.protocols import repeated
class LazyRepetition(object):
"""Repeated variable backed by a restartable generator.
Arguments:
generator_func: A stable function that returns a generator. Stable
means that the generator must be the same every time the function
is called (for the express purpose of reseting iteration).
"""
_generator_func = None
_value_type = None # Just a cache for value_type.
_watermark = 0 # Highest idx reached so far.
# The count of values. After first complete iteration this will be one
# higher than watermark.
_count = None
def __init__(self, generator_func):
if not callable(generator_func):
raise TypeError("Generator function must be callable.")
self._generator_func = generator_func
def __eq__(self, other):
if not isinstance(other, repeated.IRepeated):
return False
return self.value_eq(other)
def __iter__(self):
return self._generator_func()
def __repr__(self):
return "LazyRepetition(generator_func=%r, value_type=%r)" % (
self._generator_func, self.value_type())
# IRepeated protocol implementation (see IRepeated for behavior docs).
def getvalues(self):
"""Yields all the values from 'generator_func' and type-checks.
Yields:
Whatever 'generator_func' yields.
Raises:
TypeError: if subsequent values are of a different type than first
value.
ValueError: if subsequent iteration returns a different number of
values than the first iteration over the generator. (This would
mean 'generator_func' is not stable.)
"""
idx = 0
generator = self._generator_func()
first_value = next(generator)
self._value_type = type(first_value)
yield first_value
for idx, value in enumerate(generator):
if not isinstance(value, self._value_type):
raise TypeError(
"All values of a repeated var must be of the same type."
" First argument was of type %r, but argument %r is of"
" type %r." %
(self._value_type, value, repeated.value_type(value)))
self._watermark = max(self._watermark, idx + 1)
yield value
# Iteration stopped - check if we're at the previous watermark and raise
# if not.
if idx + 1 < self._watermark:
raise ValueError(
"LazyRepetition %r was previously able to iterate its"
" generator up to idx %d, but this time iteration stopped after"
" idx %d! Generator function %r is not stable." %
(self, self._watermark, idx + 1, self._generator_func))
# Watermark is higher than previous count! Generator function returned
# more values this time than last time.
if self._count is not None and self._watermark >= self._count:
raise ValueError(
"LazyRepetition %r previously iterated only up to idx %d but"
" was now able to reach idx %d! Generator function %r is not"
" stable." %
(self, self._count - 1, idx + 1, self._generator_func))
# We've finished iteration - cache count. After this the count will be
# watermark + 1 forever.
self._count = self._watermark + 1
def value_type(self):
if self._value_type is None:
for value in self.getvalues():
self._value_type = type(value)
break
return self._value_type
def value_eq(self, other):
"""Sorted comparison of values."""
self_sorted = ordered.ordered(self.getvalues())
other_sorted = ordered.ordered(repeated.getvalues(other))
return self_sorted == other_sorted
def value_apply(self, f):
def _generator():
for value in self.getvalues():
yield f(value)
return LazyRepetition(_generator)
# ICounted implementation:
def count(self):
if not self._count:
# Do a complete pass over the generator to cause _count to be set.
for _ in self.getvalues():
pass
return self._count
repeated.IRepeated.implicit_static(LazyRepetition)
repeated.lazy.implement(for_type=object, implementation=LazyRepetition)
counted.ICounted.implicit_static(LazyRepetition)
|