[kamaelia-list] Re: Helpful Utilities

2009-04-26 Thread Steve

Hi Michael,

Thank you very much for such a carefully thought out reply.  I
particularly enjoyed your examples illustrating your thought process.
It shed light on considerations which I had not previously thought
about.  Clearly it is a balancing act between what is best for
simplistic usages like I'm accustomed to and what scales cleanly for
more enterprise style use cases.

 So this led me to this alternative set of possibilities:

 class TCPClient(Axon.Component.component):
    delay = 0
    connect_timeout = 60
    def __init__(self, host, port, **kwargs):
       super(TCPClient, self).__init__(**kwargs)
       self.CSA = None
       self.sock = None
       self.howDied = None
       self.host = host
       self.port = port

 class Port80Client_Declarative(TCPClient):
    port = 80
    def __init__(self, host, **kwargs):
       port = kwargs.pop(port, self.port)
       super(Port80Client_Declarative, self).__init__(host, port, **kwargs)

 class KamaeliaWebsiteClient_Declarative(Port80Client):
    host = www.kamaelia.org
    def __init__(self, **kwargs):
       host = kwargs.pop(host, self.host)
       super(KamaeliaWebsiteClient_Declarative, self).__init__(host, **kwargs)
       ...

I do prefer this more explicit alternative.  Mainly it is the more
explicit nature of actually instantiating TCPClient or Port80Client or
KamaeliaWebsiteClient that appeals to me.  I don't necessarily find
value in the more explicit parameters passed to the super().__init__
call. [More on that after a quick question]

 The only downside of all this really is that it prevents this:
    TCPClient(host=www.kamaelia.org, port=80)

Why is this not possible?  My eyeball interpreter doesn't see any
reason why that would not work with what you've written.

 I have indeed, and as you'll see I've taken your thoughts on board, and I
 think reached a similar conclusion :-)

Thank you very much indeed.  I greatly appreciate your explanations.

May I suggest a slight variant on your proposed alternative?  This
variant retains the more explicit instantiations (__init__ calls from
user code) while allowing a bit of the magic back in for inheritance
(__init__ calls via super).

class TCPClient(Axon.Component.component):
   delay = 0
   connect_timeout = 60
   def __init__(self, host, port, **kwargs):
  super(TCPClient, self).__init__(**kwargs)
  self.CSA = None
  self.sock = None
  self.howDied = None
  self.host = host
  self.port = port

class Port80Client_Declarative(TCPClient):
   port = 80
   def __init__(self, host, **kwargs):
  kwargs.setdefault(port, self.port)
  kwargs['host'] = host
  # Or if = py 2.4
  # kwargs.update(host=host)
  super(Port80Client_Declarative, self).__init__(**kwargs)

class KamaeliaWebsiteClient_Declarative(Port80Client):
   # this variation moves the default declaration fully into the init
   def __init__(self, **kwargs):
  kwargs.setdefault(host, www.kamaelia.org)
  super(KamaeliaWebsiteClient_Declarative, self).__init__
(**kwargs)
  ...

This alternative would help users understand the fundamentally
required arguments (from reading or IDE tooltips / autocompletion)
while allowing relatively easy parent initialization.

 Apologies for the delay, but I really did need a holiday ;-) :-)

No worries!  I really need a holiday myself so I can fully appreciate
how necessary some away time can be.

Thanks,
Steve

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[kamaelia-list] Re: Helpful Utilities

2009-04-26 Thread Steve

Michael,

  def say(start, finish, **kwargs):

 ...     print kwargs
 ... say(finish=world, start=hello)

 {}

Yes, I'm a big fan of named parameters.  I've often wished that what
you wrote above worked as well.  It would often be nice if the
required parameters were also included in the kwargs dictionary.  But
as much as that would simplify some scenarios, I can see how it would
certainly complicate others.

 and jumping Kamaelia's support to 2.5 onwards by default. (Not suggesting
 2.6 at present since there's a wide variety of libs we use that are still
 at 2.5 as well)

Compatibility is good.  Being up to date is nice too.  I've been doing
less with Kamaelia lately and a lot with Google App Engine (2.5.2) and
I've been really missing the built-in named tuples from 2.6.

  class Port80Client_Declarative(TCPClient):
     port = 80
     def __init__(self, host, **kwargs):
        kwargs.setdefault(port, self.port)
        kwargs['host'] = host
        # Or if = py 2.4
        # kwargs.update(host=host)
        super(Port80Client_Declarative, self).__init__(**kwargs)

  class KamaeliaWebsiteClient_Declarative(Port80Client):
     # this variation moves the default declaration fully into the init
     def __init__(self, **kwargs):
        kwargs.setdefault(host, www.kamaelia.org)
        super(KamaeliaWebsiteClient_Declarative, self).__init__
  (**kwargs)
        ...

I'd like to fix up my utilities to use these idioms.  Stylistically,
do you prefer the first or second version of class provided defaults.
To simplify:

class A(Parent):
default = 'default'
def __init__(self, required, **kwargs)
kwargs.setdefault('default', self.default)
kwargs['required'] = required
super(A, self).__init__(*kwargs)

#OR

class B(Parent):
def __init__(self, required, **kwargs)
kwargs.setdefault('default', 'default')
kwargs['required'] = required
super(A, self).__init__(*kwargs)

I think B requires less typing and removes a mental indirection, but I
think style A might make it easier to spot the defaults.


 Kamaelia/Apps/SA/
...
 Incidentally, I view this namespace Kamaelia.Apps.SA - as owned by you - so if
 you don't like the names here, please let me know. If you're happy with these
 as a starting point though, let me know, and I'll merge those into trunk in
 that location. If you're not and want to modify it, please either mirror
 locally and send patches or let me know your google code ID, and I'll grant
 you access for editting what is essentially your code :-)

I think that location is fine.  Thank you.  I would like to get SVN
access to the branch though, if possible.  I'm pretty tickled with set
up I have for pulling SVN repos into my mercurial tree.  I'd like SVN
access if for no other reason that to give me an excuse to get the
mercurial - SVN process working.

 (This is part of a wider plan intended to make code contribution simpler,
 easier, more diverse and less dependent on me - with more than a little
 flagrant idea stealing from CPAN/CTAN :-)

Sounds good to me.  And thank you!

--Steve

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[kamaelia-list] Re: Helpful Utilities

2009-04-08 Thread unetright . thebashar

Hi Michael,

Thank you for the great feedback.  I'm in the process of updating all
the classes to incorporate many of your suggestions.  Before I'm
finished with that though, I have to tell you I'm really struggling
with finding peace with the Inheritable Default Values approach.

On Sun, Apr 5, 2009 at 12:53 PM, Michael Sparks - spark...@gmail.com wrote:
tickmessage = True
delay = 1
check_interval = None
def __init__(self, **argd):
super(SingleTick, self).__init__(**argd)
if self.check_interval is None or self.check_interval  self.delay:
self.check_interval = self.delay
...

   * Use of class attributes to provide default values, and enabling the
  **argd code to override the default values.
 - cf http://www.kamaelia.org/InheritableDefaultValues

First let me say that I read that link before my first submission and
chose not to go that way because I didn't feel comfortable with it.
After your feedback, I went back and re-read the wiki entry several
more times.  I'm feeling more comfortable, but there's still some
reluctance.  If possible, I'd like you to try to help me understand
how to use this more comfortably.

The most obvious problem I have with this approach is what you've
already admitted is the major downside.  You lose the self-documenting
nature of the __init__ routines.  If I have to go to the extra trouble
to document these optional[*] parameters, where is this best place to
do that?  The class docstring?  The init method docstring?

Notice my [*] on the word optional?  That is the second and more
philosophical problem I have with the Inheritable Default Values
approach.  The name of the approach implies to me that we are going to
use inheritance for default value parameters.  And parameters that
have default values are what I call optional.

But, your wiki entry shows using this approach for ALL parameters; in
effect making all parameters optional.  And this really sticks in my
craw.  Closely related to that pain is what I see in your wiki entry
of conflating two different scenarios: subclassing and factory
functions.

First let me address the all parameters are optional pain.  I have
found peace with using this inheritance method for limited
decoupling of honestly optional parameters for the purposes of
subclassing.  Let's take my simple class SingleTick.  Normally init
would take 3 parameters: a delay, a tick_mesg, and check_interval.

To me, it makes perfect sense to make the tick_mesg and check_interval
optional as there are sensible defaults.  But the delay parameter
should IMO be required.  It doesn't make sense to me to provide a
default nor to decouple future subclasses from that core parameter.
What message to send, how often to check for early termination, maybe
a callback(?) for early termination - those kind of things seem
nebulous enough to warrant the inheritance method.

So I would suggest an init signature of:
tick_mesg = True
check_interval = None
 __init__(self, delay, **kwargs)

But I don't think it makes sense to move delay into the **kwargs as
well.  And in your wiki example, I think the port and protocol
parameters falls in this same category.  It seems like those should be
non-optional arguments broken out of more flexible parameters like
socket options.

While keeping basic necessary core parameters as non-optional does add
slightly to the typing for factory functions, I don't think it's an
unreasonable trade-off to stay in line with the principle of explicit
is better than implicit.  And while more esoteric parameters might
change over time, I don't see a major risk is coupling those
fundamentally required parameters.

To boil it down, I can see this approach useful for optional
parameters with defaults, but I think it sacrifices too much clarity
for negligible gain when used for fundamentally necessary parameters.
That said, it seems you came to a different internal equilibrium and I
would really appreciate it if you could help me see it from your
perspective.

Thanks,
Steve

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



[kamaelia-list] Re: Helpful Utilities

2009-04-08 Thread unetright . thebashar
Hi Michael,

Attached is an updated python file which includes those same four
utility components.  I've incorporated most of your suggestions.  In
fact, I liked your suggested main loop simplification so much, that I
took it a step further and made them simpler yet.  I have also
employed the inheritance mechanism for the default value parameters.
 I'm not dead set against using that mechanism for all the parameters,
but I'd like you to take a look at this way first.  And like my
previous email said, I'd like you to try to help me find acceptance
with using it for non-optional parameters like you seem to prefer.

Thanks,
Steve

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---



echofuncs.py
Description: Binary data


[kamaelia-list] Re: Helpful Utilities

2009-04-05 Thread Michael Sparks

Hi Steve,


On Saturday 04 April 2009 23:30:14 Steve wrote:
 I look forward to any thoughts or comments you might have on these
 components.

For various (personal) reasons I won't be able to review this until Friday
this week. Generally they look good though and would be welcome additions.
There are a variety of changes and improvements I'd make, some which are
stylistic, but some others would improve reuse.

As an example of what I mean, I'd probably change SingleTick to be more like
this:

class SingleTick(Axon.ThreadedComponent.threadedcomponent):
'''
This threaded component will wait delay seconds then send True out it's
outbox and shutdown.  You can specify an optional check_interval which
will cause the component to periodically check it's control inbox for
early termination signals.
'''
Inboxes = {
 inbox: Ignored,
 control: Sending a message here will cause the component to 
terminate,
}
Outboxes = {
 outbox : If the delay is reached uninterrupted the tickmessage - 
default 'True' is sent here,
 signal : producerFinished() if not interrrupted, otherwise the 
interruption/termination message,
}
tickmessage = True
delay = 1
check_interval = None
def __init__(self, **argd):
super(SingleTick, self).__init__(**argd)
if self.check_interval is None or self.check_interval  self.delay:
self.check_interval = self.delay

def main(self):
delay_until = time.time() + self.delay
self.pause(self.check_interval)
now = time.time()
while not self.dataReady('control') now  delay_until:
remainder = delay_until - now
if remainder  self.check_interval and remainder  0:
self.pause(remainder)
else:
self.pause(self.check_interval)
now = time.time()

if self.dataReady('control'):
self.send(self.recv('control'), 'signal')
else:
self.send(self.tickmessage, 'outbox')
self.send(producerFinished(self), 'signal')

The differences here include:
   * More meta data around use of inboxes  outboxes. (Enabling the doc
  generator to extract this)
  - eg http://www.kamaelia.org/Components/pydoc/Kamaelia.File.Append.Append

   * Use of class attributes to provide default values, and enabling the
  **argd code to override the default values.
 - cf http://www.kamaelia.org/InheritableDefaultValues

   * Logic change in loop to make the code paths clearer.

Regards,


Michael.
-- 
http://yeoldeclue.com/blog
http://twitter.com/kamaelian
http://www.kamaelia.org/Home

--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---