예제 #1
0
    def test_cannot_store_twice(self):
        @fpn.pipe_node()
        def pn():
            return 12

        pni = fpn.PipeNodeInput()

        with self.assertRaises(KeyError):
            (pn | fpn.store("a") | fpn.store("a"))[pni]
예제 #2
0
def approach_pipe_4b():

    a = (PN4.name_count_per_year(lambda n: n.lower().startswith('lesl'))
         | PN4.percent | fpn.store('lesl'))

    b = (PN4.name_count_per_year(lambda n: n.lower().startswith('dana'))
         | PN4.percent | fpn.store('dana'))

    f = (PN4.merge_gender_data(lesl=a, dana=b)
         | PN4.year_range(1920, 2000)
         | fpn.store('merged') * 100
         | PN4.plot('gender.png')
         | PN4.open_plot)

    pni = PN4.PNI('/tmp')
    f[pni]

    xlsx_fp = os.path.join(pni.output_dir, 'output.xlsx')
    xlsx = pd.ExcelWriter(xlsx_fp)
    for k, df in pni.store_items():
        df.to_excel(xlsx, k)
    xlsx.save()

    os.system('libreoffice --calc ' + xlsx_fp)
예제 #3
0
def approach_pipe_2():

    f = (PN2.load_data_dict(FP_ZIP) | PN2.gender_count_per_year
         | PN2.percent * 100 | PN2.year_range(1900, 2000)
         | PN2.plot | PN2.open_plot)

    # with store and recall to do multiple operations

    f = (PN2.load_data_dict(FP_ZIP) | PN2.gender_count_per_year
         | PN2.percent * 100
         | fpn.store('gpcent')
         | PN2.year_range(1900, 2000) | PN2.plot | PN2.open_plot
         | fpn.recall('gpcent')
         | PN2.year_range(2001, 2015) | PN2.plot | PN2.open_plot)

    #fpn.run(f) # this implicitly passes a PipeNodeInput
    f(pn_input=fpn.PipeNodeInput())
예제 #4
0
def pn():
    # if we are willing to adjust our functions about, we can do even more with PipeNodes. PipeNodes have a protocal; they have to be called in a certain way, and have certain expectations regarding arguments. PipeNodes are created through decorators. Decorated functions receive PipeNode qwargs

    a = fpn.pipe_node(lambda **kwargs: kwargs[fpn.PREDECESSOR_RETURN] + 'a')

    # another way of doing the same thing
    @fpn.pipe_node
    @fpn.pipe_kwarg_bind(fpn.PREDECESSOR_RETURN)
    def a(s):
        return s + 'a'

    # capturing the initial input is not automatic
    init = fpn.pipe_node(lambda **kwargs: kwargs[fpn.PN_INPUT])

    @fpn.pipe_node_factory
    def cat(chars, **kwargs):
        return kwargs[fpn.PREDECESSOR_RETURN] + chars

    f = init | a | cat('b') | cat('c')

    print(f(pn_input='*'))
    assert f(pn_input='*') == '*abc'

    # can also be done as the following

    print(f(**{fpn.PN_INPUT: '*'}))
    assert f(**{fpn.PN_INPUT: '+'}) == '+abc'

    print(f['*'])
    assert f['*'] == '*abc'

    # with pipenodes, all nodes have access to the PN_INPUT through the common kwargs

    @fpn.pipe_node_factory
    def replace_init(chars, **kwargs):
        return kwargs[fpn.PREDECESSOR_RETURN].replace(kwargs[fpn.PN_INPUT],
                                                      chars)

    f = init | a | cat('b') | cat('c') * 2 | replace_init('+')
    print(f['*'])
    assert f['*'] == '+abc+abc'

    # as already shown pipe-nodes can take arguments; those arguments can be pipe nodes themselves

    @fpn.pipe_node_factory
    def interleave(chars, **kwargs):
        pred = kwargs[fpn.PREDECESSOR_RETURN]
        post = []
        for i, c in enumerate(pred):
            post.append(c)
            post.append(chars[i % len(chars)])
        return ''.join(post)

    h = init | cat('@@') | cat('__') * 2
    f = init | a | cat('b') | cat('c') * 3 | replace_init('+') | interleave(h)

    print(f['*'])
    assert f['*'] == '+*a@b@c_+_a*b@c@+_a_b*c@'

    # if we want to use a PN expression more than once, we can store it and recall it later. To do so, we need to use a PipeNodeInput or itse subclass

    class Input(fpn.PipeNodeInput):
        def __init__(self, chars):
            super().__init__()
            self.chars = chars

    # we nee dot change our init function to read the chars attr
    input_init = fpn.pipe_node(lambda **kwargs: kwargs[fpn.PN_INPUT].chars)

    p = input_init | cat('www') | fpn.store('p')
    q = input_init | cat('@@') | cat('__') * 2 | fpn.store('q')
    r = input_init | a | cat(fpn.recall('p')) | cat('c') * 3 | interleave(
        fpn.recall('q'))
    f = fpn.call(p, q, r)

    pni = Input('x')
    print(f[pni])

    pni = Input('x')  # must create a new one
    assert f[pni] == 'xxa@x@w_w_wxc@x@a_x_wxw@w@c_x_axx@w@w_w_cx'
예제 #5
0
    def test_complex_pipeline(self):
        @fpn.pipe_node_factory(fpn.PREDECESSOR_RETURN)
        def multiply(prev, val):
            return prev * val

        @fpn.pipe_node(fpn.PN_INPUT, fpn.PREDECESSOR_RETURN)
        def add_pni(pni, prev):
            return prev + pni.value

        @fpn.pipe_node
        def init(**kwargs):
            return 12

        @fpn.pipe_node_factory
        def func(arg1, arg2, **kwargs):
            return (kwargs[fpn.PN_INPUT].value *
                    arg1) + (kwargs[fpn.PREDECESSOR_RETURN] / arg2)

        class Operations:
            DELTA = 0.23

            def __init__(self, factor):
                self.factor = factor

            @fpn.classmethod_pipe_node
            def add_delta(cls, **kwargs):
                return cls.DELTA + kwargs[fpn.PREDECESSOR_RETURN]

            @fpn.staticmethod_pipe_node_factory(fpn.PREDECESSOR_RETURN)
            def bound_prev(prev, lower, upper):
                return max(min(prev, lower), upper)

            @fpn.pipe_node(fpn.PN_INPUT, fpn.PREDECESSOR_RETURN)
            def adj_by_factor(self, pni, prev):
                return self.factor * (pni.value - prev)

        op = Operations(23.717)

        expr = (init
                | add_pni
                | fpn.store("A")
                | multiply(-8)
                | func(13, 7)
                | fpn.store("B")
                | op.add_delta
                | Operations.add_delta
                | op.bound_prev(0, 100)
                | fpn.store("C")
                | multiply(130.2)
                | Operations.bound_prev(100, 200)
                | op.adj_by_factor
                | fpn.store("D")
                | fpn.recall("A")
                | op.adj_by_factor
                | fpn.recall("B")
                | op.adj_by_factor
                | fpn.recall("C")
                | op.adj_by_factor
                | add_pni)

        class PNI(fpn.PipeNodeInput):
            def __init__(self, value):
                super().__init__()
                self.value = value

        pni = PNI(-89)
        post = expr[pni]

        # Manually calculate
        expected = 12
        expected += pni.value
        A = expected
        expected *= -8
        expected = (pni.value * 13) + (expected / 7)
        B = expected
        expected += op.DELTA
        expected += Operations.DELTA
        expected = max(min(expected, 0), 100)
        C = expected
        expected *= 130.2
        expected = max(min(expected, 100), 200)
        expected = op.factor * (pni.value - expected)
        D = expected
        expected = op.factor * (pni.value - C)
        expected += pni.value

        self.assertEqual(-4571.513, expected)
        self.assertEqual(-4571.513, post)

        self.assertEqual(A, pni._store["A"])
        self.assertEqual(B, pni._store["B"])
        self.assertEqual(C, pni._store["C"])
        self.assertEqual(D, pni._store["D"])

        self.assertEqual(pni.store_items(), dict(A=A, B=B, C=C, D=D).items())