On Oct 5, 1:46 pm, Jason Baker <jason.ba...@ttu.edu> wrote:
> Grammar nazi alert:
>
>  "To stop this generator, you need to call it's .stop() method. The
> wrapper could do this"

It's a sketch - rather than a proposal for immediate merge - hence the
request for feedback. Pedantry at this stage does not fall into the
category of helpful feedback. (It makes people, me included, think
twice about posting a sketch something for feedback on the concepts)

> Moving on to subjects with a little bit more substance, suppose I have
> a generator function Foo that I wrap using one of these decorators.
> What exactly will happen if I call Foo?

Like all decorators, Foo then no longer binds to the original version
of Foo. In this case, rather than returning a generator, it returns a
component.

I suspected this:

Pipeline(
    follow('/var/log/system.log'),
    grep(None, ".*pants.*"),
    printer(None)
).run()

would be relatively obvious.

After all, Pipeline links and activates components, not generators,
therefore the decorated generator functions return components that use
the generator functions for their logic, rather than the generator
functions directly.

In this case, the 2 decorators are used to use the logic embodied by
the generator to control a component. This opens up a variety of
possibilities.

> This isn't entirely clear to me by tracing the sourcecode.

This is why I split into two portions, at least when I reposted.
Specifically, one part shows a working illustration of how this would
be used:

http://code.google.com/p/kamaelia/source/browse/trunk/Sketches/MPS/AxonDecorators/example.py

... and I noted that the names "blockingProducer" &
"TransformerGenComponent" are non ideal - but then it is inside /
Sketches...

The other was an initial implementation - which is primarily proof of
concept that this can even be done - which can be found here:

http://code.google.com/p/kamaelia/source/browse/trunk/Sketches/MPS/AxonDecorators/decorators.py

blockingProducer is a fairly traditional/simple decorator. For anyone
who've written lots of decorators, there's a handful of issues with
that bare approach (cf the Michele Simionato's decorator module for
more details), but it's fine as a basic proof of concept.

The decorator TransformerGenComponent is slightly odd in that it
returns a class rather than a function which reuses/configures a
function. This is primarily because that was the more obvious approach
at the time. I'll be refactoring it to match the blocking producer
format.

Out of these two files though, the most important one is not the
implementation, but the idea & API as used in the example file:

http://code.google.com/p/kamaelia/source/browse/trunk/Sketches/MPS/AxonDecorators/example.py

For example, in an earlier thread, I posted this syntax/decorator
illustration:

@GeneratorComponent(Inboxes = ["inbox", "control"],
                    Outboxes = ["outbox", "signal"])
def Tracer(self):
    while 1:
        for msg in self.Inbox("inbox"):
            print self.tag, str(msg)
            self.send(msg, "outbox")
        self.pause()
        yield 1

However, this looked like one step too far towards voodoo for Steve &
IIRC John agreed. In retrospect, I agree, though it could be a
convenient shortcut.

Furthermore a suggested alternative syntax like this:

# Becomes a subsumed generator by one in the wrapper that handles
control and
# moving yielded values to the outbox. Looks like a standard simple
generator.
@GeneratorPipelineComponent
def Tracer(inbox):
    for msg in inbox:
        print "> ", str(msg)
        yield msg

Has some unresolvable problems without massively complicating
GeneratorPipelineComponent, or without reformulating that example like
this:

@TransformerGenComponent
def Tracer(inbox):
    while 1:
        for msg in inbox():
            print "> ", str(msg)
            yield msg
        yield

My question was fundamentally this: does the following code look clear
enough to follow /roughly/ what's going on at a glance, or is it too
unclear.

@blockingProducer
def follow(fname):
    f = file(fname)
    f.seek(0,2) # go to the end
    while True:
        l = f.readline()
        if not l: # no data
            time.sleep(.1)
        else:
            yield l

@TransformerGenComponent
def grep(lines, pattern):
    regex = re.compile(pattern)
    while 1:
        for l in lines():
            if regex.search(l):
                yield l
        yield

@TransformerGenComponent
def printer(lines):
    while 1:
        for line in lines():
            sys.stdout.write(line)
            sys.stdout.flush()
        yield

Pipeline(
    follow('/var/log/system.log'),
    grep(None, ".*pants.*"),
    printer(None)
).run()

If the above is clear & readable - ie you read this as it follows a
system file, greps for a pattern and prints it, that's good. If it
isn't the implementation is irrelevant. If it is clear, the goalposts
change to making the implementation nicer, maintainable and ideally
unsurprising.

I've had positive comments elsewhere, so my impression based on those
is that this *may* be a nice idea.

*ho hum*


Michael.

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"kamaelia" group.
To post to this group, send email to kamaelia@googlegroups.com
To unsubscribe from this group, send email to 
kamaelia+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/kamaelia?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to