Skip to content

Commit

Permalink
Add flow.Filter (with tests and extensive docs). Update documentation…
Browse files Browse the repository at this point in the history
… for newer Sphinx.
  • Loading branch information
ynikitenko committed May 1, 2021
1 parent 365c8bd commit e934e77
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 4 deletions.
8 changes: 4 additions & 4 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
sys.path.insert(0, os.path.abspath('../../'))

def setup(app):
app.add_javascript('copybutton.js')
app.add_stylesheet('custom.css')
app.add_javascript('custom.js')
app.add_javascript('https://cdn.jsdelivr.net/npm/clipboard@1/dist/clipboard.min.js')
app.add_js_file('copybutton.js')
app.add_css_file('custom.css')
app.add_js_file('custom.js')
app.add_js_file('https://cdn.jsdelivr.net/npm/clipboard@1/dist/clipboard.min.js')

highlight_language = 'python'

Expand Down
3 changes: 3 additions & 0 deletions docs/source/flow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Flow
Cache
DropContext
End
Filter
Print

.. Count
Expand Down Expand Up @@ -66,6 +67,8 @@ which didn't fit other categories.
:members:
.. autoclass:: End
:members:
.. autoclass:: Filter
:members:
.. autoclass:: Print
:members:
..
Expand Down
2 changes: 2 additions & 0 deletions lena/flow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
get_example_bin,
)
from lena.flow.zip import Zip
from .filter import Filter


__all__ = [
# elements
'Cache', 'Count', 'DropContext', 'End', 'Print',
'Chain', 'CountFrom', 'ISlice',
'Filter',
'ReadROOTFile',
'ReadROOTTree',
'Zip',
Expand Down
58 changes: 58 additions & 0 deletions lena/flow/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from .selectors import Selector as _Selector


class Filter():
"""Filter values from flow."""

def __init__(self, selector):
"""*selector* is a boolean function.
If it returns ``True``, the value passes :class:`Filter`.
If *selector* is not callable, it is converted to
a :class:`.Selector`.
If the conversion could not be done,
:exc:`.LenaTypeError` is raised.
Note
----
:class:`Filter` appeared in Lena only in version 0.4.
There may be better alternatives to using this element:
- don't produce values that you will discard later.
If you want to select data from a specific file,
read only that file.
- use a custom class. *SelectPosition("border")* is more
readable and maintainable than a :class:`Filter`
with many conditions, and it is also more *cohesive*
if you group several options
like "center" or "top" in a single place.
If you make a selection, it can be useful
to add information about that to the *context*
(and :class:`Filter` does not do that).
This doesn't mean that we recommend against this class:
sometimes it can be quick and useful, and if one's
class name provides absolutely no clue what it does,
a general :class:`Filter` would be more readable.
"""
if not callable(selector):
selector = _Selector(selector)
self._selector = selector

def fill_into(self, element, value):
"""Fill *value* into an *element* if
*selector(value)* is ``True``.
*Element* must have a *fill(value)* method.
"""
if self._selector(value):
element.fill(value)

def run(self, flow):
"""Yield values from the *flow* for which
the *selector* is ``True``.
"""
return (val for val in flow if self._selector(val))
# or
# for val in flow:
# if self._selector(val):
# yield event
4 changes: 4 additions & 0 deletions lena/math/vector3.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ def __init__(self, v):
)
self._v = list(map(float, v))

# todo: add fromcylindrical?
# make set_ and get_ functions private. What's the use of them?
# Make constructor accept no list, but just 3 numbers.

@classmethod
def fromspherical(cls, r, phi, theta):
r"""Construct vector3 from spherical coordinates.
Expand Down
1 change: 1 addition & 0 deletions lena/output/latex_to_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def __init__(self, overwrite=False, verbose=1, create_command=None):
texfile_name]
"""
self._overwrite = overwrite
# todo: make verbose private.
self.verbose = verbose
if create_command and not callable(create_command):
raise lena.core.LenaTypeError(
Expand Down
35 changes: 35 additions & 0 deletions tests/flow/test_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import pytest
import lena

from lena.flow import Filter, Selector

from tests.examples.fill import StoreFilled


def test_filter():
# initialization argument must be callable, a Selector,
# or should be able to be converted to a Selector
with pytest.raises(lena.core.LenaTypeError):
Filter(1)

# filter with a selector works
s = Selector([int, str])
f0 = Filter(s)

## Test run
f1 = Filter([int, str])
data = [1, 2, "s", [], (), (3, {})]
res_data = [1, 2, "s", (3, {})]
assert list(f0.run(data)) == res_data # list(f1.run(data))
assert list(f1.run(data)) == [1, 2, "s", (3, {})]

# filter with a function works
fun = lambda val: val
f2 = Filter(fun)
assert list(f2.run(data + [0, 4])) == [1, 2, "s", (3, {}), 4]

## Test fill_into
sf1 = StoreFilled()
for val in data:
f1.fill_into(sf1, val)
assert sf1.list == res_data
8 changes: 8 additions & 0 deletions tests/math/test_vector3.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def test_eq():
v1 > 0


def test_operations():
v1 = vector3([3, 4, 5])
v1 *= 2
assert v1 == vector3([6, 8, 10])
v1 /= 2
assert v1 == vector3([3, 4, 5])


def test_cylindrical():
v1 = vector3([3, 4, 5])
# rho computed
Expand Down

0 comments on commit e934e77

Please sign in to comment.