Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
The volume of these discussions is (as expected) growing beyond any 
reasonable bounds; I hope the BDFL can find time to read them but I'm 
starting to doubt he will.  Since obviously we're not going to convince 
each other, and it seems to me we're at least getting close to 
pinpointing our differences, maybe we should try to jointly develop an 
"executive summary" of our differences and briefly stated pros and cons 
-- a PEP is _supposed_ to have such a section, after all.  Anyway, for 
now, here goes another LONG mail...:

On 2005 Jan 10, at 22:38, Phillip J. Eby wrote:
   ...
If interfaces can ensure against Liskov violations in instances of 
their subclasses, then they can follow the "case (a)" fast path, 
sure.
Inheriting from an interface (in Guido's current proposal, as per his 
Artima blog) is a serious commitment from the inheritor's part; 
inheriting from an ordinary type, in real-world current practice, 
need not be -- too many cases of assumed covariance, for example, are 
around in the wild, to leave NO recourse in such cases and just 
assume compliance.
I understand that, sure.  But I don't understand why we should add 
complexity to PEP 246 to support not one but *two* bad practices: 1) 
implementing Liskov violations and 2) adapting to concrete classes.  
It is only if you are doing *both* of these that this extra feature is 
needed.
s/support/deal with/ .  If I was designing a "greenfield" system, I'd 
love nothing better than making a serious split between concrete 
classes (directly instantiable), abstract classes (subclassable), and 
protocols (adaptable-to).  Scott Meyer's suggestion, in one of his 
Effective C++ books, to never subclass a concrete class, has much to 
recommend itself, in particular.  But in the real world people do want 
to subclass concrete classes, just as much as they want covariance AND, 
I'll bet, adapting to classes, too, not just to interfaces seen as a 
separate category from classes.  I think PEP 246 should deal with the 
real world.  If the BDFL thinks otherwise, and believes that in this 
case Python should impose best practices rather than pragmatically deal 
with the way people's minds (as opposed to type-system maths) appear to 
work, I'll be glad to recast the PEP in that light.

Contrary to what you state, adapting to concrete (instantiable) classes 
rather than abstract (not directly instantiable) one is not necessary 
to make the mechanism required, by the way.  Consider an abstract class 
such as:

class Abstract(object):
def tp1(self):
''' template method 1 (calls hook method 1) '''
def tp2(self):
''' template method 2 (calls hook method 2) '''
def hook1(self): raise NotImplementedError
def hook2(self): raise NotImplementedError
One could subclass it just to get tp1...:
class Dubious(Abstract):
def hook1(self): ''' implementing just hook1 '''
Now, instantiating d=Dubious() is dubious practice, but, absent 
specific checks, it "works", as long as only d.hook1() and d.tp1() are 
ever called -- never d.hook2() nor d.tp2().

I would like adapt(d, Abstract) to fail.  I'm not claiming that the 
ability to have a __conform__ method in Dubious to specifically block 
this adaptation is anywhere like a perfect solution, mind you -- it 
does require some change to the source of Dubious, for example.  I'm 
just saying that I think it's better than nothing, and that is where we 
seem to disagree.

If it were to support some kind of backward compatibility, that would 
be understandable.  However, in practice, I don't know of anybody 
using adapt(x,ConcreteClass), and even if they did, the person 
subclassing ConcreteClass will need to change their subclass to raise 
LiskovViolation, so why not just switch to delegation?
Because delegation doesn't give you _easy_ access to Template Method 
design patterns which may well be the one reason you're subclassing 
Abstract in the first place.  TP hinges on a method calling some 
self.dothis(), self.dothat() hook methods; to get it via delegation 
rather than inheritance requires a more complicated arrangement where 
that 'self' actually belongs to a "private" concrete class which 
delegates some things back to the "real" class.  In practice, 
inheritance as a means of code reuse (rather than as a pristine 
Liskovian assertion of purity) is quite popular because of that.  C++ 
essentially acknowledges this fact by allowing _private_ inheritance, 
essentially meaning "I'm reusing that code but don't really mean to 
assert IS-A"; the effects of private inheritance could be simulated by 
delegation to a private auxiliary class, but the extra indirections and 
complications aren't negligible costs in terms of code complexity and 
maintainability.  In Python, we don't distinguish between private 
inheritance (to just reuse code) and ordinary inheritance (assumed to 
imply Liskov sub.), but that doesn't make the need go away.  The 
__conform__ raising LiskovViolation could be seen as a way 

Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 10, at 23:19, Phillip J. Eby wrote:
   ...
As I said, after more thought, I'm actually less concerned about the 
performance than I am about even remotely encouraging the combination 
of Liskov violation *and* concrete adaptation
As per other msg, abstract classes have just the same issues as 
concrete ones.

If Ka-Ping Yee's idea (per Artima cmts on BDFL blog) of having 
interfaces supply template methods too ever flies, the issue would 
arise there, too (a BDFL comment with a -1 suggests it won't fly, 
though).

targets.  But, if "after the dust settles" it turns out this is going 
to be supported after all, then we can worry about the performance if 
need be.

Note, however, that your statements actually support the idea of *not* 
adding a special case for Liskov violators.  If newer code uses 
interfaces, the Liskov-violation mechanism is useless.  If older code 
doesn't have __conform__, it cannot possibly *use* the 
Liskov-violation mechanism.
Adding __conform__ to a class to raise a LiskovViolation when needed is 
a TINY change compared to the refactoring needed to use 
template-methods without subclassing.

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 10, at 23:15, Thomas Heller wrote:
Alex Martelli <[EMAIL PROTECTED]> writes:
PEP: 246
Title: Object Adaptation
Minor nit (or not?): You could provide a pointer to the Liskov
substitution principle, for those reader that aren't too familiar with
that term.
Excellent idea, thanks.
Besides, the text mentions three times that LiskovViolation is a
subclass of AdaptionError (plus once in the ref impl section).
Always hard to strike a balance between what's repeated and what isn't, 
I'll try to get a better one on this point on the next edit.

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 10, at 19:34, Phillip J. Eby wrote:
   ...
IMO it's more desirable to support abstract base classes than to allow 
classes to "opt out" of inheritance when testing conformance to a base 
class.  If you don't have an "is-a" relationship to your base class, 
you should be using delegation, not inheritance.  (E.g. 'set' has-a 
'dict', not 'set' is-a 'dict', so 'adapt(set,dict)' should fail, at 
least on the basis of isinstance checking.)
C++'s private inheritance explicitly acknowledges how HANDY subclassing 
can be for pure implementation purposes; we don't have private 
inheritance but that doesn't mean subclassing becomes any less handy;-)

The other problem with a Liskov opt-out is that you have to explicitly 
do a fair amount of work to create a LiskovViolation-raising subclass;
A TINY amount of work.  Specifically, starting from:
class X(Abstract):
""" most of X omitted """
def hook1(self):
""" implement hook1 so as to get tm1 from Abstract """
if self.foo() > self.bar():
self.baz()
else:
self.fie = self.flup - self.flum
return self.zap()
all you have to do is ADD
def __conform__(self, protocol):
if issubclass(protocol, Abstract):
raise LiskovViolation
that's all.
(See my big post about what Abstract is, with template methods tm1 and 
tm2 respectively using hook methods hook1 and hook2: X doesn't 
implement hook2).

 that work would be better spent migrating to use delegation instead 
of inheritance, which would also be cleaner and more comprehensible 
code than writing a __conform__ hack to announce your bad style in 
having chosen to use inheritance where delegation is more appropriate. 
 ;)
The amount of effort is MUCH vaster.  Essentially RECODE everything so 
s/thing like:

class X(object):
""" most of X omitted """
class PrivateAuxiliaryClass(Abstract):
def __init__(self, x):
self.x = x
def hook1(self):
return self.x.hook1()
def __init__(self):
self.pac = self.PrivateAuxiliaryClass(self)
# rest of X.__init__ omitted
def tm1(self):
return self.pac.tm1()
this isn't just a tiny band-aid to say "I really wish the language had 
private inheritance because I'm using Abstract as a base just for code 
reuse" -- it's a rich and complex restructuring, and in fact it's just 
the beginning; now you have a deuced reference loop between each 
instance x of X, and its x.pac, so you'll probably want to pull in 
weakref, too, to avoid giving too much work to the cyclical garbage 
collector.

Basically, rephrasing private inheritance with containment and 
delegation is a lot of messy work, and results in far more complicated 
structures.  And instead of paying the tiny price of a __conform__ call 
at adaptation time, you pay the price of delegating calls over and over 
at each x.tm1() call, so it's unlikely performance will improve.

By pushing Liskov conformance without supporting "private inheritance" 
or its equivalent, you're really pushing people to use much more 
complicated and sophisticated structures of objects than "private 
inheritance" affords when properly used... and the LAST thing OO 
programmers need is any encouragement towards more complicated 
structures!-)

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 10, at 18:59, Phillip J. Eby wrote:
At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote:
As a practical matter, all of the existing interface systems (Zope, 
PyProtocols, and even the defunct Twisted implementation) treat 
interface inheritance as guaranteeing substitutability for the base 
interface, and do so transitively.
An additional data point, by the way: the Eclipse Java IDE has an 
adaptation system that works very much like PEP 246 does, and it 
appears that in a future release they intend to support automatic 
adapter transitivity, so as to avoid requiring each provider of an 
interface to "provide O(n^2) adapters when writing the nth version of 
an interface."  IOW, their current release is transitive only for 
interface inheritance ala Zope or Twisted; their future release will 
be transitive for adapter chains ala PyProtocols.
This is definitely relevant prior art, so thanks for pointing it out.  
If interfaces change so often that 'n' can become worryingly high, this 
is a valid concern.  In my world, though, published interfaces do NOT 
change as often as to require such remedies;-).

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 11:01, Alex Martelli wrote:
On 2005 Jan 10, at 18:59, Phillip J. Eby wrote:
At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote:
As a practical matter, all of the existing interface systems (Zope, 
PyProtocols, and even the defunct Twisted implementation) treat 
interface inheritance as guaranteeing substitutability for the base 
interface, and do so transitively.
An additional data point, by the way: the Eclipse Java IDE has an 
adaptation system that works very much like PEP 246 does, and it 
appears that in a future release they intend to support automatic 
adapter transitivity, so as to avoid requiring each provider of an 
interface to "provide O(n^2) adapters when writing the nth version of 
an interface."  IOW, their current release is transitive only for 
interface inheritance ala Zope or Twisted; their future release will 
be transitive for adapter chains ala PyProtocols.
This is definitely relevant prior art, so thanks for pointing it out.  
If interfaces change so often that 'n' can become worryingly high, 
this is a valid concern.  In my world, though, published interfaces do 
NOT change as often as to require such remedies;-).
...that was a bit too flippant -- I apologize.  It DOES happen that 
interfaces keep changing, and other situations where "adapter-chain 
transitivity" is quite handy do, absolutely!, occur, too.  Reflecting 
on Microsoft's QI (QueryInterface), based on a very strong injunction 
against changing interfaces and yet mandating transitivity, points that 
out -- that's prior art, too, and a LOT more of it than Eclipse can 
accumulate any time soon, considering how long COM has been at the 
heart of Microsoft's components strategy, how many millions of 
programmers have used or abused it.  Still, QI's set of constraints, 
amounting to a full-fledged equivalence relationship among all the 
"adapters" for a single underlying "object", is, I fear, stronger than 
we can impose (so it may be that Eclipse is a better parallel, but I 
know little of it while COM is in my bones, so that's what I keep 
thinking of;-).

So, I see transitivity as a nice thing to have _IF_ it's something that 
gets explicitly asserted for a certain adapter -- if the adapter has to 
explicitly state to the system that it "isn't lossy" (maybe), or "isn't 
noisy" (perhaps more useful), or something like that... some amount of 
reassurance about the adapter that makes it fully safe to use in such a 
chain.

Maybe it might suffice to let an adapter which IS 'lossy' (or, more 
likely, one that is 'noisy') state the fact.  I'm always reluctant by 
instinct to default to convenient but risky behavior, trusting 
programmers to explicitly assert otherwise when needed; but in many 
ways this kind of design is a part of Python and works fine (_with_ the 
BDFL's fine nose/instinct for making the right compromise between 
convenience and safety in each case, of course).

I'm still pondering the "don't adapt an adapter" suggestion, which 
seems a sound one, and yet also seems to be, intrinsically, what 
transitivity-by-chaining does.  Note that QI does not suffer from this, 
because it lets you get the underlying object identity (IUnknown) from 
any interface adapter.  Maybe, just maybe, we should also consider that 
-- a distinguished protocol bereft of any real substance but acting as 
a flag for "real unadapted object identity".  Perhaps we could use 
'object' for that, at least if the flow of logic in 'adapt' stays as in 
the current PEP 246 draft (i.e., __conform__ is given a chance before 
isinstance triggers -- so, all adapters could __conform__ to object by 
returning the underlying object being adapted, while other objects 
without such a feature in __conform__ would end up with 'adapt(x, 
object) is x').  Or, if object in this role turns out to be confusing, 
IDentity (;-) or some other specially designed protocol.

If we had this ability to "get at the underlying object" we could at 
least write clearer axioms about what transitivity must mean, as well 
as, help out with the "adapting an adapter" problems.  E.g., imagine:

def f(x: IFoo, y: IFoo):
if x is y: ...
that wouldn't work if adapt(x, IFoo) returns a separate adapter each 
time, which is the most likely situation (think, again, of str->file 
adaptation by StringIO wrapping); but recovering underlying identities 
by "adapt(x, object) is adapt(y, object)" would work.

I don't think that IUnknown or an equivalent, per se, can do *instead* 
of the need to have an adapter explicitly state it's non-noisy (or VV). 
 Besides the need to check for object identity, which is pretty rare 
except when writing axioms, invariants or pre/post-conds;-), the 
IUnknown equivalent would perhaps be more of a conceptual/philosophical 
'prop' than a practically useful feature -- while I see the ability to 
block unintended consequences of inheritance and transitivity (or even 
better, state explicitly when those consequences are wanted, even if 
that shoul

Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Armin Rigo
Hi Phillip,

On Mon, Jan 10, 2005 at 04:38:55PM -0500, Phillip J. Eby wrote:
> Your new proposal does not actually fix this problem in the absence of 
> tp_conform/tp_adapt slots; it merely substitutes possible confusion at the 
> metaclass/class level for confusion at the class/instance level.

I think that what Alex has in mind is that the __adapt__() and __conform__()
methods should work just like all other special methods for new-style classes.  
The confusion comes from the fact that the reference implementation doesn't do 
that.  It should be fixed by replacing:

   conform = getattr(type(obj), '__conform__', None)

with:

   for basecls in type(obj).__mro__:
   if '__conform__' in basecls.__dict__:
   conform = basecls.__dict__['__conform__']
   break
   else:
   # not found

and the same for '__adapt__'.

The point about tp_xxx slots is that when implemented in C with slots, you get
the latter (correct) effect for free.  This is how metaconfusion is avoided in
post-2.2 Python.  Using getattr() for that is essentially broken.  Trying to
call the method and catching TypeErrors seems pretty fragile -- e.g. if you
are calling a __conform__() which is implemented in C you won't get a Python
frame in the traceback either.


A bientot,

Armin
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH/RFC for AF_NETLINK support

2005-01-11 Thread Jp Calderone
On Tue, 11 Jan 2005 08:54:42 +0100, "\"Martin v. Löwis\"" <[EMAIL PROTECTED]> 
wrote:
>Philippe Biondi wrote:
> > I've done a small patch to use linux AF_NETLINK sockets (see below).
> > Please comment!
> 
> I have a high-level comment - python-dev is normally the wrong place
> for patches; please submit them to sf.net/projects/python instead.
> 
> Apart from that, the patch looks fine.
> 
> > Is there a reason for recvmsg() and sendmsg() not to be implemented
> > yet in socketmodule ?
> 
> I'm not sure what you mean by "implemented": these functions are
> implemented by the operating system, not in the socketmodule.
> 
> If you ask "why are they not exposed to Python yet?": There has been no
> need to do so, so far. What do I get with recvmsg that I cannot get with
> recv/recvfrom just as well?

  Everything that recvmsg() does.  recv() and recvfrom() give you 
"regular" bytes - data sent to the socket using send() or sendto().  
recvmsg() gives you messages - data sent to the socket using sendmsg().  
There is no way to receive messages by using recv() or recvfrom() (and 
no way to send them using send() or sendto()).

  Inversely, I believe send() and recv() can be implemented in terms of
sendmsg() and recvmsg().  Perhaps we should get rid of socket.send() and
socket.recv()? 

  Other things that sendmsg() and recvmsg() can do include passing file 
descriptors, receiving notice of OOB TCP data, peek at bytes from the 
kernel's buffer without actually reading them, and implement 
scatter/gather IO functions (although you'd probably just want to wrap 
and use writev() and readv() instead).

  Jp
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH/RFC for AF_NETLINK support

2005-01-11 Thread Jp Calderone
On Tue, 11 Jan 2005 01:32:52 +, David Wilson <[EMAIL PROTECTED]> wrote:
>On Mon, Jan 10, 2005 at 05:17:49PM +0100, Philippe Biondi wrote:
> 
> > I've done a small patch to use linux AF_NETLINK sockets (see below).
> > Please comment!
> 
> As of 2.6.10, a very useful new netlink family was merged -
> NETLINK_KOBJECT_UEVENT. I'd imagine quite a lot of interest from Python
> developers for NETLINK support will come from this new interface in the
> coming years.
> 
> [snip]
> 
> I would like to see (optional?) support for this before your patch is
> merged. I have a long-term interest in a Python-based service control /
> init replacement / system management application, for use in specialised
> environments. I could definately use this. :)

  Useful indeed, but I'm not sure why basic NETLINK support should be 
held up for it?

  Jp
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH/RFC for AF_NETLINK support

2005-01-11 Thread Philippe Biondi
On Tue, 11 Jan 2005, [ISO-8859-1] "Martin v. Löwis" wrote:

> Philippe Biondi wrote:
> > I've done a small patch to use linux AF_NETLINK sockets (see below).
> > Please comment!
>
> I have a high-level comment - python-dev is normally the wrong place
> for patches; please submit them to sf.net/projects/python instead.

OK, I'll post it here.

>
> Apart from that, the patch looks fine.

Fine!

>
> > Is there a reason for recvmsg() and sendmsg() not to be implemented
> > yet in socketmodule ?
>
> I'm not sure what you mean by "implemented": these functions are
> implemented by the operating system, not in the socketmodule.
>
> If you ask "why are they not exposed to Python yet?": There has been no
> need to do so, so far. What do I get with recvmsg that I cannot get with
> recv/recvfrom just as well?

You can have access to ancillary messages. You can, for example transmit
credentials or file descriptors through unix sockets, which is very
interesting for privilege separation.


-- 
Philippe Biondi   SecDev.org
Security Consultant/R&D http://www.secdev.org
PGP KeyID:3D9A43E2  FingerPrint:C40A772533730E39330DC0985EE8FF5F3D9A43E2

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 12:41 PM 1/11/05 +, Armin Rigo wrote:
The point about tp_xxx slots is that when implemented in C with slots, you get
the latter (correct) effect for free.  This is how metaconfusion is avoided in
post-2.2 Python.  Using getattr() for that is essentially broken.  Trying to
call the method and catching TypeErrors seems pretty fragile -- e.g. if you
are calling a __conform__() which is implemented in C you won't get a Python
frame in the traceback either.
An excellent point.  The issue hasn't come up before now, though, because 
there aren't any __conform__ methods written in C in the field that I know 
of.  Presumably, if there are any added to CPython in future, it will be 
because there's a tp_conform slot and it's needed for built-in types, in 
which case the problem is again moot for the implementation.

(FYI, C methods implemented in Pyrex add a dummy frame to the traceback 
such that you see the file and line number of the original Pyrex source 
code.  Very handy for debugging.)

Anyway, I agree that your version of the code should be used to form the 
reference implementation, since the purpose of the reference implementation 
is to show the complete required semantics.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 16:34, Phillip J. Eby wrote:
   ...
Anyway, I agree that your version of the code should be used to form 
the reference implementation, since the purpose of the reference 
implementation is to show the complete required semantics.
Great, one point at last on which we fully agree -- thanks Armin!-)
I was waiting for BDFL feedback before editing the PEP again, but if 
none is forthcoming I guess at some point I'll go ahead and at least to 
the edits that are apparently not controversial, like this one.  I'd 
like to have a summary of controversial points and short pro and con 
args, too, but I'm not unbiased enough to write it all by myself...;-)

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Michael Chermside
Phillip:

I think you must inhabit a far more perfect world than I do.

You say, for instance, that:
> ...-1 if this introduces a performance penalty [...] just to
> support people who want to create deliberate Liskov violations.
> I personally don't think that we should pander to Liskov
> violators

... but in my world, people violate Liskov all the time, even
in languages that attempt (unsuccessfully) to enforce it. [1]

You say that:
> I think one should adapt primarily to interfaces, and
> interface-to-interface adaptation should be reserved for
> non-lossy, non-noisy adapters.

... but in my world, half the time I'm using adaptation to
correct for the fact that someone else's poorly-written
code requests some class where it should have just used
an interface.

You seem to inhabit a world in which transitivity of adaptation
can be enforced. But in my world, people occasionally misuse
adaptation because they think they know what they're doing
or because they're in a big hurry and it's the most convenient
tool at hand.

I wish I lived in your world, but I don't.

-- Michael Chermside

[1] - Except for Eiffel. Eiffel seems to do a pretty good job
   of enforcing it.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] logging class submission

2005-01-11 Thread Stephan Stapel
Dear people on the dev list!
I hope that this is the right environment to post my submission request 
(I'm new to the scene).

I have modified the RotatingFileHandler of the logging module to create 
a daily rolling file handler.

As it works quite good, I would like to suggest inclusion into the 
standard logging module of Python. I know that the code is quite trivial 
but the class solves the problem of the RotatingFileHandler that you 
don't know where to find a certain log entry. By using dates within the 
log file name, one can exactly determine which log file to observe when 
searching for specific errors.

I hope you like to code and/ or point to improvements on it and finally 
move it into the logging module.

cheers,
Stephan
Here comes the code:
# Copyright 2004-2005 by Stephan Stapel <[EMAIL PROTECTED]>. All 
Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of Stephan Stapel
# not be used in advertising or publicity pertaining to distribution
# of the software without specific, written prior permission.
#
# STEPHAN STAPEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# STEPHAN STAPEL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
DAMAGES OR
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 
OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import logging
from datetime import date
import string
class DailyRollingFileHandler(logging.FileHandler):
"""
The class is based on the standard RotatingFileHandler class from the
official logging module.
It rolls over each day, thus one log file per day is created in the 
form
myapp-2005-01-07.log, myapp-2005-01-08.log etc.
"""

def __init__(self, filename, mode="a"):
"""
Open the specified file and use it as the stream for logging.
Rollover occurs whenever the day changes.
The names of the log files each contain the date when they were
created. Thus if the filename "myapp.log" was used, the log files
each have look like myapp-2005-01-07.log etc.
The date is inserted at the position of the last '.' in the 
filename
if any or simply appended to the given name if no dot was present.
"""
self.currentDay   = date.today()
# create the logfile name parts (base part and extension)
nameparts = string.split(string.strip(filename), ".")
self.filestub = ""
self.fileext  = ""

# remove empty items
while nameparts.count("") > 0:
nameparts.remove("")
if len(nameparts) < 2:
self.filestub = nameparts[0]
else:
# construct the filename
for part in nameparts[0:-2]:
self.filestub += part + "."
self.filestub += nameparts[-2]
self.fileext   = "." + nameparts[-1]
logging.FileHandler.__init__(self, self.getFilename(), mode)
def getFilename(self):
return self.filestub + "-" + self.currentDay.isoformat() + 
self.fileext

def doRollover(self):
"""
Do a rollover, as described in __init__().
"""
self.stream.close()
self.currentDay   = date.today()
self.baseFilename = self.getFilename()
self.stream = open(self.baseFilename, "w")
def emit(self, record):
"""
Emit a record.
Output the record to the file, catering for rollover as described
in doRollover().
"""
msg = "%s\n" % self.format(record)
self.stream.seek(0, 2)  #due to non-posix-compliant Windows 
feature
if date.today() != self.currentDay:
self.doRollover()
logging.FileHandler.emit(self, record)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] logging class submission

2005-01-11 Thread Batista, Facundo
Title: RE: [Python-Dev] logging class submission





[Stephan Stapel]


#- # Copyright 2004-2005 by Stephan Stapel <[EMAIL PROTECTED]>. All 
#- Rights Reserved.
#- #
#- # Permission to use, copy, modify, and distribute this 
#- software and its
#- # documentation for any purpose and without fee is hereby granted,
#- # provided that the above copyright notice appear in all 
#- copies and that
#- # both that copyright notice and this permission notice appear in
#- # supporting documentation, and that the name of Stephan Stapel
#- # not be used in advertising or publicity pertaining to distribution
#- # of the software without specific, written prior permission.


There's a license issue here?


.    Facundo


Bitácora De Vuelo: http://www.taniquetil.com.ar/plog
PyAr - Python Argentina: http://pyar.decode.com.ar/



  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

ADVERTENCIA.


La información contenida en este mensaje y cualquier archivo anexo al mismo, son para uso exclusivo del destinatario y pueden contener información confidencial o propietaria, cuya divulgación es sancionada por la ley.

Si Ud. No es uno de los destinatarios consignados o la persona responsable de hacer llegar este mensaje a los destinatarios consignados, no está autorizado a divulgar, copiar, distribuir o retener información (o parte de ella) contenida en este mensaje. Por favor notifíquenos respondiendo al remitente, borre el mensaje original y borre las copias (impresas o grabadas en cualquier medio magnético) que pueda haber realizado del mismo.

Todas las opiniones contenidas en este mail son propias del autor del mensaje y no necesariamente coinciden con las de Telefónica Comunicaciones Personales S.A. o alguna empresa asociada.

Los mensajes electrónicos pueden ser alterados, motivo por el cual Telefónica Comunicaciones Personales S.A. no aceptará ninguna obligación cualquiera sea el resultante de este mensaje.

Muchas Gracias.



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 18:27, Michael Chermside wrote:
   ...
... but in my world, people violate Liskov all the time, even
in languages that attempt (unsuccessfully) to enforce it. [1]
   ...
[1] - Except for Eiffel. Eiffel seems to do a pretty good job
   of enforcing it.
...has Eiffel stopped its heroic efforts to support covariance...?  
It's been years since I last looked seriously into Eiffel (it was one 
of the languages we considered as a successor to Fortran and C as main 
application language, at my previous employer), but at that time that 
was one of the main differences between Eiffel (then commercial-only) 
and its imitator (freeware) Sather: Sather succumbed to mathematical 
type-theory and enforced contravariance, Effel still tried to pander 
for how the human mind works by allowing covariance (which implies a 
Liskov violation and is probably the main serious reason for it) and 
striving horrendously to shoehorn it in.  So what's the score now...?

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 10:34 AM 1/11/05 +0100, Alex Martelli wrote:
The volume of these discussions is (as expected) growing beyond any 
reasonable bounds; I hope the BDFL can find time to read them but I'm 
starting to doubt he will.  Since obviously we're not going to convince 
each other, and it seems to me we're at least getting close to pinpointing 
our differences, maybe we should try to jointly develop an "executive 
summary" of our differences and briefly stated pros and cons -- a PEP is 
_supposed_ to have such a section, after all.
Yes, hopefully we will have sufficient convergence to do that soon.  For 
example, I'm going to stop arguing against the use case for Liskov 
violation, and try looking at alternative implementations.  If those don't 
work out, I'll stop objecting to that item altogether.


the effects of private inheritance could be simulated by delegation to a 
private auxiliary class, but the extra indirections and complications 
aren't negligible costs in terms of code complexity and maintainability.
Ah.  Well, in PEAK, delegation of methods or even read-only attributes is 
trivial:

 class SomeObj(object):
 meth1 = meth2 = meth3 = binding.Delegate('_delegatee')
 _delegatee = binding.Make(OtherClass)
This class will create a private instance of OtherClass for a given SomeObj 
instance the first time meth1, meth2, or meth3 are retrieved from that 
instance.

I bring this up not to say that people should use PEAK for this, just 
explaining why my perspective was biased; I'm so used to doing this that I 
tend to forget it's nontrivial if you don't already have these sorts of 
descriptors available.


Maybe the ability to ``fake'' __class__ can help, but right now I don't 
see how, because setting __class__ isn't fake at all -- it really affects 
object behavior and type:

...
So, it doesn't seem to offer a way to fake out isinstance only, without 
otherwise affecting behavior.
Python 2.3.4 (#53, May 25 2004, 21:17:02) [MSC v.1200 32 bit (Intel)] on 
win32
Type "copyright", "credits" or "license()" for more information.
>>> class Phony(object):
def getClass(self): return Dummy
__class__ = property(getClass)
>>> class Dummy: pass
>>> Phony().__class__

>>> isinstance(Phony(),Dummy)
True
Unfortunately, this still doesn't really help, because isinstance() seems 
to apply to a union of __class__ and type:

>>> isinstance(Phony(),Phony)
True
So, lying about __class__ doesn't fix the issue because you're still 
considered isinstance, unless adapt() just uses __class__ and doesn't use 
isinstance().


I can give no example at all in which adapting to a concrete class is a 
_good_ idea, and I tried to indicate that in the PEP.  I just believe that 
if adaptation does not offer the possibility of using concrete classes as 
protocols, but rather requires the usage as protocols of some specially 
blessed 'interface' objects or whatever, then PEP 246 will never fly, (a) 
because it would then require waiting for the interface thingies to 
appear, and (b) because people will find it pragmatically useful to just 
reuse the same classes as protocols too, and too limiting to have to 
design protocols specifically instead.
Okay, I strongly disagree on this point, because there are people using 
zope.interface and PyProtocols today, and they are *not* using concrete 
classes.  If PEP 246 were to go into Python 2.5 without interface types, 
all that would change is that Zope and PyProtocols would check to see if 
there is an adapt() in builtins and, if not, install their own version.

PEP 246 would certainly be more useful *with* some kind of interface type, 
but Guido has strongly implied that PEP 246 won't be going in *without* 
some kind of interface type, so it seems to me academic to say that PEP 246 
needs adaptation to concrete types based on isinstance().

In fact, maybe we should drop isinstance() from PEP 246 altogether, and 
only use __conform__ and __adapt__ to implement adaptation.  Thus, to say 
that you conform to a concrete type, you have to implement __conform__.  If 
this is done, then an abstract base used as an interface can have a 
__conform__ that answers 'self' for the abstract base used as a protocol, 
and a Liskov-violating subclass can return 'None' for the abstract 
base.  Inheritance of __conform__ will do the rest.

This approach allows concrete classes and Liskov violations, but simplifies 
adapt() since it drops the need for isinstance and for the Liskov 
exception.  Further, we could have a default object.__conform__ that does 
the isinstance check.  Then, a Liskov-violating subclass just overrides 
that __conform__ to block the inheritance it wants to block.

This approach can't work with a separately-distributed PEP 246 
implementation, but it should work quite well for a built-in implementation 
and it's backward compatible with the semantics expected by "old" PEP 246 
implementations.  It means that all objects will have a tp_conform slot 
that will hav

RE: [Python-Dev] logging class submission

2005-01-11 Thread Batista, Facundo
Title: RE: [Python-Dev] logging class submission





[Stephan Stapel]


#- > There's a license issue here? 
#- 
#- I was given the advise to use this license. If this license 
#- prohibts inclusion into Python, how should I re-license the code?


I just was asking. Who gave you the advise?


.    Facundo


Bitácora De Vuelo: http://www.taniquetil.com.ar/plog
PyAr - Python Argentina: http://pyar.decode.com.ar/



  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

ADVERTENCIA.


La información contenida en este mensaje y cualquier archivo anexo al mismo, son para uso exclusivo del destinatario y pueden contener información confidencial o propietaria, cuya divulgación es sancionada por la ley.

Si Ud. No es uno de los destinatarios consignados o la persona responsable de hacer llegar este mensaje a los destinatarios consignados, no está autorizado a divulgar, copiar, distribuir o retener información (o parte de ella) contenida en este mensaje. Por favor notifíquenos respondiendo al remitente, borre el mensaje original y borre las copias (impresas o grabadas en cualquier medio magnético) que pueda haber realizado del mismo.

Todas las opiniones contenidas en este mail son propias del autor del mensaje y no necesariamente coinciden con las de Telefónica Comunicaciones Personales S.A. o alguna empresa asociada.

Los mensajes electrónicos pueden ser alterados, motivo por el cual Telefónica Comunicaciones Personales S.A. no aceptará ninguna obligación cualquiera sea el resultante de este mensaje.

Muchas Gracias.



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 10:59 AM 1/11/05 +0100, Alex Martelli wrote:
all you have to do is ADD
def __conform__(self, protocol):
if issubclass(protocol, Abstract):
raise LiskovViolation
that's all.
That will raise a TypeError if protocol is not a class or type, so this 
could probably serve as an example of how difficult it is to write a good 
Liskov-violating __conform__.  :)

Actually, there's another problem with it; if you do this:
class Y(X): pass
class Z(Y): pass
then 'adapt(Z(),Y)' will now fail because of a Liskov violation.  It should 
really check for 'protocol is Abstract' or 'protocol in (Abstract,..)' in 
order to avoid this issue.


Basically, rephrasing private inheritance with containment and delegation 
is a lot of messy work, and results in far more complicated 
structures.  And instead of paying the tiny price of a __conform__ call at 
adaptation time, you pay the price of delegating calls over and over at 
each x.tm1() call, so it's unlikely performance will improve.
Well, as I mentioned in my other post, such inheritance is a lot simpler 
with PEAK, so I've probably forgotten how hard it is if you're not using 
PEAK.  :)  PEAK also caches the delegated methods in the instance's 
__dict__, so there's virtually no performance penalty after the first access.

Again, not an argument that others should use PEAK, just an explanation as 
to why I missed this point; I've been using PEAK's delegation features for 
quite some time and so tend to think of delegation as something relatively 
trivial.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] logging class submission

2005-01-11 Thread Barry Warsaw
On Tue, 2005-01-11 at 12:58, Batista, Facundo wrote:
> [Stephan Stapel]
> 
> #- > There's a license issue here? 
> #- 
> #- I was given the advise to use this license. If this license 
> #- prohibts inclusion into Python, how should I re-license the code?
> 
> I just was asking. Who gave you the advise?

Here's a link to the PSF contribution form:

http://www.python.org/psf/contrib.html

This contains links to the recommended licenses for software that might
be included in Python.

-Barry



signature.asc
Description: This is a digitally signed message part
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] logging class submission

2005-01-11 Thread Stephan Stapel
> I just was asking. Who gave you the advise?

someon in a german python forum. I'll change the license asap.

I'm just curious, but do I really have to use the contributor agreement etc.? I 
mean I'm just trying to submit a small class, no big framework.

cheers,

Stephan

Verschicken Sie romantische, coole und witzige Bilder per SMS!
Jetzt neu bei WEB.DE FreeMail: http://freemail.web.de/?mc=021193

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 09:27 AM 1/11/05 -0800, Michael Chermside wrote:
Phillip:
I think you must inhabit a far more perfect world than I do.
You say, for instance, that:
> ...-1 if this introduces a performance penalty [...] just to
> support people who want to create deliberate Liskov violations.
> I personally don't think that we should pander to Liskov
> violators
I've since dropped both the performance objection and the objection to 
supporting Liskov violation; in a more recent post I've proposed an 
alternative algorithm for allowing it, that has a simpler implementation.


You say that:
> I think one should adapt primarily to interfaces, and
> interface-to-interface adaptation should be reserved for
> non-lossy, non-noisy adapters.
... but in my world, half the time I'm using adaptation to
correct for the fact that someone else's poorly-written
code requests some class where it should have just used
an interface.
PEP 246 adaptation?  Or are you talking about some other language?  (I ask 
out of curiosity.)

I agree that if it's possible to adapt to concrete types, people will do 
so.  However, I think we all agree that this isn't a great idea and should 
still be considered bad style.  That's not the same thing as saying it 
should be forbidden, and I haven't said it should be forbidden.


You seem to inhabit a world in which transitivity of adaptation
can be enforced. But in my world, people occasionally misuse
adaptation because they think they know what they're doing
or because they're in a big hurry and it's the most convenient
tool at hand.
How is this different from abuse of *any* language feature that you're then 
forced to work around?  Are you saying we should not provide a feature 
because *some* people will abuse the feature?  I don't understand.

If you allow interface inheritance, you're just as susceptible to an 
invalid adaptation path, and in my experience this is more likely to bite 
you unintentionally, mainly because interface inheritance works differently 
than class inheritance (which of course is used more often).  Do you want 
to prohibit interface inheritance, too?

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 11:59 AM 1/11/05 +0100, Alex Martelli wrote:
On 2005 Jan 11, at 11:01, Alex Martelli wrote:
On 2005 Jan 10, at 18:59, Phillip J. Eby wrote:
At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote:
As a practical matter, all of the existing interface systems (Zope, 
PyProtocols, and even the defunct Twisted implementation) treat 
interface inheritance as guaranteeing substitutability for the base 
interface, and do so transitively.
An additional data point, by the way: the Eclipse Java IDE has an 
adaptation system that works very much like PEP 246 does, and it appears 
that in a future release they intend to support automatic adapter 
transitivity, so as to avoid requiring each provider of an interface to 
"provide O(n^2) adapters when writing the nth version of an 
interface."  IOW, their current release is transitive only for interface 
inheritance ala Zope or Twisted; their future release will be transitive 
for adapter chains ala PyProtocols.
This is definitely relevant prior art, so thanks for pointing it out.
If interfaces change so often that 'n' can become worryingly high, this 
is a valid concern.  In my world, though, published interfaces do NOT 
change as often as to require such remedies;-).
FWIW, I don't believe that by "nth version" the original author wasn't 
referring to changed versions of the same interface, but was instead maybe 
trying to say that N interfaces that adapt to IFoo, when IFoo has M 
interfaces that it can be adapted to, means that N*M adapters are required 
in all, if adapter composition isn't possible.


"adapters" for a single underlying "object", is, I fear, stronger than we 
can impose (so it may be that Eclipse is a better parallel, but I know 
little of it while COM is in my bones, so that's what I keep thinking of;-).
Fair enough.  I think Eclipse's *implementation* maps fairly directly onto 
PEP 246, except that __conform__ is replaced by a 'getAdapter()' method, 
and an AdapterManager is used to look up adapters in place of both 
__adapt__ and the PEP 246 registry.  So, it is much closer to PEP 246 than 
COM, in that COM all adaptation is managed by the object, and it cannot be 
externally adapted.  (At least, the last I looked at COM many years ago it 
was the case; maybe that has changed now?)


So, I see transitivity as a nice thing to have _IF_ it's something that 
gets explicitly asserted for a certain adapter -- if the adapter has to 
explicitly state to the system that it "isn't lossy" (maybe), or "isn't 
noisy" (perhaps more useful), or something like that... some amount of 
reassurance about the adapter that makes it fully safe to use in such a chain.
Maybe, although I think in our other thread we may be converging on 
definitions of lossy and noisy that are such we can agree that it's not 
really a problem.  (I hope.)


Maybe it might suffice to let an adapter which IS 'lossy' (or, more 
likely, one that is 'noisy') state the fact.
I don't see a valid use case for implementing such a thing as an 
automatically-invoked adapter.


  I'm always reluctant by instinct to default to convenient but risky 
behavior, trusting programmers to explicitly assert otherwise when 
needed; but in many ways this kind of design is a part of Python and 
works fine (_with_ the BDFL's fine nose/instinct for making the right 
compromise between convenience and safety in each case, of course).
Proposal: let adaptation implemented via __conform__ be nontransitive, and 
adaptation via __adapt__ or the adapter registry be transitive.

This would mean that lossy or noisy adapters could be implemented as an 
implicitly-executed explicit conversion, but only directly on a particular 
concrete class and its subclasses, thereby further limiting the scope and 
impact of a lossy or noisy adapter.

Also, think about this: technically, if you implement lossy or noisy 
adaptation in __conform__, it *isn't* lossy or noisy, because you have to 
do it in the class -- which means that as the class' author, you have 
decreed it to have such semantics.  However, if you are a third party, you 
will have to explicitly invoke the lossy or noisy adapter.

IOW, if you globally register an adapter (with either the interface or the 
global registry), you are guaranteeing that your adaptation is not lossy or 
noisy.  Otherwise, you need to put it in __conform__ or use it explicitly.


I'm still pondering the "don't adapt an adapter" suggestion, which seems a 
sound one, and yet also seems to be, intrinsically, what 
transitivity-by-chaining does.  Note that QI does not suffer from this, 
because it lets you get the underlying object identity (IUnknown) from any 
interface adapter.  Maybe, just maybe, we should also consider that -- a 
distinguished protocol bereft of any real substance but acting as a flag 
for "real unadapted object identity".  Perhaps we could use 'object' for 
that, at least if the flow of logic in 'adapt' stays as in the current PEP 
246 draft (i.e., __conform__ is given a chance before i

RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Michael Chermside
I wrote:
> >... but in my world, half the time I'm using adaptation to
> >correct for the fact that someone else's poorly-written
> >code requests some class where it should have just used
> >an interface.

Phillip replies:
> PEP 246 adaptation?  Or are you talking about some other language?
> (I ask out of curiosity.)

Well, it's partly just a rhetorical device here. I mean PEP 246
adaption, but (unlike you!) I'm not actually using it yet (aside
from playing around to try things out), really I'm just guessing
how I WOULD be using it if it were part of core python.

> I agree that if it's possible to adapt to concrete types, people will do
> so.  However, I think we all agree that this isn't a great idea and should
> still be considered bad style.

I'd agree except for the case where I am trying to pass an object
into code which is misbehaving. If we do add type declarations that
trigger an adapt() call, then people WILL write poor code which
declares concrete types, and I will find myself writing __conform__
methods to work around it. In this case, I'm the one making use of
adaption (the original author was just expecting a TypeError), but
what I'm doing isn't (IMO) bad style.

> >You seem to inhabit a world in which transitivity of adaptation
> >can be enforced. But in my world, people occasionally misuse
> >adaptation because they think they know what they're doing
> >or because they're in a big hurry and it's the most convenient
> >tool at hand.
>
> How is this different from abuse of *any* language feature that you're
> then forced to work around?  Are you saying we should not provide a
> feature because *some* people will abuse the feature?  I don't
> understand.

If we're just recomending that people design for transitivity, then I
don't have a problem (although see Alex's fairly good point illustrated
with LotsOfInfo, PersonName, and FullName -- I found it convincing).
But I was under the impression that the point of transitivity was to
make it "required", then automatically walk chains of adaptions. Then
I fear one case of mis-used adaption could "poison" my entire adaption
mechanism. The N^2 explosion of pairwise-only adapters scares me less,
because I think in most real situations N will be small.

> If you allow interface inheritance, you're just as susceptible to an
> invalid adaptation path, and in my experience this is more likely to
> bite you unintentionally, mainly because interface inheritance works
> differently than class inheritance (which of course is used more
> often).  Do you want to prohibit interface inheritance, too?

Hmm. Sounds like you're making a point here that's important, but which
I don't quite get. Can you elaborate? I certainly hadn't intended to
prohibit interface inheritance... how exactly does it "bite" one?

-- Michael Chermside



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Clark C. Evans
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote:
| * Replacing LiskovViolation is possible by dropping type/isinstance 
| checks from adapt(), and adding an isinstance check to 
| object.__conform__; Liskov violators then override __conform__ in their 
| class to return None when asked to conform to a protocol they wish to 
| reject, and return super().__conform__ for all other cases.  This 
| achieves your use case while simplifying both the implementation and the 
| usage.

I'd rather not assume that class inheritance implies substitutability,
unless the class is "marked" as an interface (assuming that one 
doesn't have interfaces).  I'd like it to be explicit -- a bit of a
nudge to remind a developer to verify substitutability is a good
thing. In this scenerio, a LiskovViolation exception isn't needed
(aside, I don't see the rationale for the exception: to prevent
third party adapters?). Could we make a boilerplate __conform__
which enables class-based substitutability a well-known decorator?

| * In my experience, incorrectly deriving an interface from another is the 
| most common source of unintended adaptation side-effects, not adapter 
| composition

It'd be nice if interfaces had a way to specify a test-suite that
could be run against a component which claims to be compliant.   For
example, it could provide invalid inputs and assert that the proper
errors are returned, etc.

Best,

Clark


-- 
Clark C. Evans  Prometheus Research, LLC.
http://www.prometheusresearch.com/
o   office: +1.203.777.2550 
  ~/ ,  mobile: +1.203.444.0557 
 //
((   Prometheus Research: Transforming Data Into Knowledge
 \\  ,
   \/- Research Exchange Database
   /\- Survey & Assessment Technologies
   ` \   - Software Tools for Researchers
~ *
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread David Ascher
Alex Martelli wrote:
On 2005 Jan 10, at 23:15, Thomas Heller wrote:
Alex Martelli <[EMAIL PROTECTED]> writes:
PEP: 246
Title: Object Adaptation

Minor nit (or not?): You could provide a pointer to the Liskov
substitution principle, for those reader that aren't too familiar with
that term.

Excellent idea, thanks.
Terminology point: I know that LiskovViolation is technically correct, 
but I'd really prefer it if exception names (which are sometimes all 
users get to see) were more informative for people w/o deep technical 
background.  Would that be possible?

--david
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Michael Chermside
David Ascher writes:
> Terminology point: I know that LiskovViolation is technically correct,
> but I'd really prefer it if exception names (which are sometimes all
> users get to see) were more informative for people w/o deep technical
> background.  Would that be possible?

I don't see how. Googling on Liskov immediately brings up clear
and understandable descriptions of the principle that's being violated.
I can't imagine summarizing the issue more concisely than that! What
would you suggest? Including better explanations in the documentation
is a must, but "LiskovViolation" in the exception name seems unbeatably
clear and concise.

-- Michael Chermside

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 10:47 AM 1/11/05 -0800, Michael Chermside wrote:
I'd agree except for the case where I am trying to pass an object
into code which is misbehaving. If we do add type declarations that
trigger an adapt() call, then people WILL write poor code which
declares concrete types, and I will find myself writing __conform__
methods to work around it. In this case, I'm the one making use of
adaption (the original author was just expecting a TypeError), but
what I'm doing isn't (IMO) bad style.
Agreed.  However, assuming that you're declaring a "clean" adaptation, 
perhaps it should be registered with the global registry rather than 
implemented in __conform__, which would be less work for you.


If we're just recomending that people design for transitivity, then I
don't have a problem (although see Alex's fairly good point illustrated
with LotsOfInfo, PersonName, and FullName -- I found it convincing).
It's a bit misleading, however; if the target protocol allows for "nulls", 
then it's allowed to have nulls.  If it doesn't allow nulls, then the 
adaptation is broken.  Either way, it seems to me to work out, you just 
have to decide which way you want it.


But I was under the impression that the point of transitivity was to
make it "required", then automatically walk chains of adaptions.
I don't have a problem with making some part of the adaptation process 
avoid transitivity, such as hand-implemented __conform__ methods.


 Then
I fear one case of mis-used adaption could "poison" my entire adaption
mechanism. The N^2 explosion of pairwise-only adapters scares me less,
because I think in most real situations N will be small.
Well, Eclipse is a pretty good example of a large N, and I know that both 
Twisted and Zope developers have occasionally felt the need to do 
"double-dip" adaptation in order to work around the absence of transitive 
adapter composition in their adaptation systems.


> If you allow interface inheritance, you're just as susceptible to an
> invalid adaptation path, and in my experience this is more likely to
> bite you unintentionally, mainly because interface inheritance works
> differently than class inheritance (which of course is used more
> often).  Do you want to prohibit interface inheritance, too?
Hmm. Sounds like you're making a point here that's important, but which
I don't quite get. Can you elaborate? I certainly hadn't intended to
prohibit interface inheritance... how exactly does it "bite" one?
If you derive an interface from another interface, this is supposed to mean 
that your derived interface promises to uphold all the promises of the base 
interface.  That is, your derived interface is always usable where the base 
interface is required.

However, oftentimes one mistakenly derives an interface from another while 
meaning that the base interface is *required* by the derived interface, 
which is similar in meaning but subtly different.  Here, you mean to say, 
"IDerived has all of the requirements of IBase", but you have instead said, 
"You can use IDerived wherever IBase is desired".

But now, suppose that you have class Foo, which has an adapter defined to 
IDerived, and which is looked up for you by IDerived.__adapt__ and 
IBase.__adapt__.  Then, if you pass a Foo instance to a function that 
expects an *IBase*, then the function will end up with an IDerived.

Sometimes this is not at all what you want, at which point I normally go 
back and copy the relevant methods from IBase to IDerived and remove the 
inheritance relationship.

This problem exists in Zope's adaptation system as well as in 
PyProtocols.  I have found that I am far less likely to have an adaptation 
problem from defining a questionable adapter, than I am to have one from 
wrongly-used inheritance.  I am now more careful about the inheritance, but 
it's difficult because intuitively an interface defines a *requirement*, so 
it seems logical to inherit from an interface in order to add requirements!

Now, in the case where both an IBase and an IDerived adapter exist, Zope 
and PyProtocols prefer to use the IBase adapter when an IBase is 
requested.  But this doesn't address the problem case, which is where there 
is no IBase-only adaptation.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 01:50 PM 1/11/05 -0500, Clark C. Evans wrote:
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote:
| * Replacing LiskovViolation is possible by dropping type/isinstance
| checks from adapt(), and adding an isinstance check to
| object.__conform__; Liskov violators then override __conform__ in their
| class to return None when asked to conform to a protocol they wish to
| reject, and return super().__conform__ for all other cases.  This
| achieves your use case while simplifying both the implementation and the
| usage.
I'd rather not assume that class inheritance implies substitutability,
Hm, you should take that up with Alex then, since that is what his current 
PEP 246 draft does.  :)  Actually, the earlier drafts did that too, so I'm 
not sure why you want to change this now.

What I've actually suggested here actually allows for 
inheritance=substitutability as the default, but also makes it trivially 
changeable for any given inheritance hierarchy by overriding __conform__ at 
the base of that hierarchy, and without introducing a special exception 
class to do it.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Concrete proposals for PEP 246

2005-01-11 Thread Phillip J. Eby
To save everyone from having to wade through the lengthy discussions 
between Alex and I, and to avoid putting all the summarization burden on 
Alex, I thought I would start a new thread listing my concrete proposals 
for PEP 246 changes, and summarizing my understanding of the current 
agreements and disagreements we have.  (Alex, please correct me if I have 
misrepresented your position in any respects.)

First, I propose to allow explicitly-declared Liskov violations, but using 
a different mechanism than the one Alex has proposed.  Specifically, I wish 
to remove all type or isinstance checking from the 'adapt()' 
function.  But, the 'object' type should have a default __conform__ that is 
equivalent to:

class object:
def __conform__(self,protocol):
if isinstance(protocol,ClassTypes) and isinstance(self,protocol):
return self
return None
and is inherited by all object types, including types defined by extension 
modules, unless overridden.

This approach provides solid backward compatibility with the previous 
version of PEP 246, as long as any user-implemented __conform__ methods 
call their superclass __conform__.  But, it also allows Liskov-violating 
classes to simply return 'None' to indicate their refusal to conform to a 
base class interface, instead of having to raise a special exception.  I 
think that, all else being equal, this is a simpler implementation approach 
to providing the feature, which Alex and others have convinced me is a 
valid (if personally somewhat distasteful) use case.

Second: Alex has agreed to drop the "cast" terminology, since its meanings 
in various languages are too diverse to be illuminating.  We have instead 
begun creeping towards agreement on some concepts such as "lossy" or 
"noisy" conversions.  I think we can also drop my original "lossy" term, 
because "noisy" can also imply information loss and better explains the 
real issue anyway.

A "noisy" conversion, then, is one where the conversion "makes up" 
information that was not implicitly present in the original, or drops 
information that *alters the semantics of the information that is 
retained*.  (This phrasing gets around Alex's LotsOfInfo example/objection, 
while still covering loss of numeric precision; mere narrowing and renaming 
of attributes/methods does not alter the semantics of the retained 
information.)

Adaptation is not recommended as a mechanism for noisy conversions, because 
implicit changes to semantics are a bad idea.  Note that this is actually 
independent of any transitivity issues -- implicit noisy conversion is just 
a bad idea to start with, which is why 'someList[1.2]' raises a TypeError 
rather than implicitly converting 1.2 to an integer!  If you *mean* to drop 
the .2, you should say so, by explicitly converting to an integer.

(However, it *might* be acceptable to implicitly convert 1.0 to an integer; 
I don't currently have a strong opinion either way on that issue, other 
than to note that the conversion is not "noisy" in that case.)

Anyway, I think that the current level of consensus between Alex and myself 
on the above is now such that his comparison to casting could now be 
replaced by some discussion of noisy vs. non-noisy (faithful? 
high-fidelity?) conversion, and the fact that adaptation is suitable only 
for the latter, supplemented by some examples of noisy conversion use cases 
and how to transform them into non-noisy constructs.  The string->file vs. 
string->file_factory example is a particularly good one, I think, because 
it shows how to address a common, practical issue.

Third: (Proposed) The PEP should explicitly support classic classes, or 
else there is no way to adapt exception instances.  (Yes, I have actually 
done this; peak.web adapts exception instances to obtain appropriate 
handlers, for example.)

Fourth: The principal issue from the original discussion that remains open 
at this time is determining specific policies or recommendations for 
addressing various forms of transitivity, which we have delved into a 
little bit.  (By  "open" I jut mean that there is no proposal for this 
issue currently on the table, not to imply that my proposals are not also 
"open" in the sense of awaiting consensus.)

Anyway, the kinds of transitivity we're discussing are:
  1. interface inheritance transitivity (i.e. adapt(x,IBase) if 
adapt(x,IDerived) and IDerived inherits from IBase)

  2. adapter composition transitivity (i.e. adapt(x,ISome) if 
adapt(x,IOther) and there is a general-purpose ISome->IOther adapter available.

These are mostly issues for the design of an interface system (implementing 
__adapt__) and for the design of a global adapter registry.  I don't think 
it's practical to implement either kind of transitivity on the __conform__ 
side, at least not for hand-written __conform__ methods.

To summarize current PEP 246 implementations' choices on this issue, Zope 
implements type 1 transiti

Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 20:44, Phillip J. Eby wrote:
   ...
If we're just recomending that people design for transitivity, then I
don't have a problem (although see Alex's fairly good point 
illustrated
with LotsOfInfo, PersonName, and FullName -- I found it convincing).
It's a bit misleading, however; if the target protocol allows for 
"nulls", then it's allowed to have nulls.  If it doesn't allow nulls, 
then the adaptation is broken.  Either way, it seems to me to work 
out, you just have to decide which way you want it.
NULLs are allowed, but *PRAGMATICALLY* they shouldn't be used except 
where there's no alternative.

Is the concept of *PRAGMATICS* so deucedly HARD for all of your 
eggheads?!  Maybe a full-credits course in linguistics should be 
mandatory for CS major or wherever you got your sheepskin[s].

In terms of syntax and semantics, a TCP/IP stack which just dropped all 
packet instantly would be compliant with the standards.  No GUARANTEE 
that any given packet will be delivered is ever written down anywhere, 
after all.

The reason such a TCP/IP stack would NOT be a SENSIBLE implementation 
of the standards is PRAGMATICS.  The stack is supposed to do a 
best-effort ATTEMPT to deliver packets, dammit!  That may be hard to 
formalize mathematically, but it makes all the difference in the world 
between a silly joke and a real-world tool.

My best example of pragmatics in linguistics: if I state...:
""" I never strangle python-dev posters with the initials PJE in months 
with an "R" in them """

I am saying nothing that is false or incorrect or misleading, in terms 
of syntax and semantics.  This assertion is grammatically correct and 
semantically true.

Does this mean you should worry come May...?  Not necessarily, because 
the assertion is _pragmatically_ dubious.  *PRAGMATICALLY*, in all 
natural languages, when I state "I never do X under condition Y" 
there's an implication that "condition Y" DOES have something to do 
with the case -- that if condition Y DOESN'T hold then my assurance 
about not doing X weakens.  If condition Y has nothing to do with my 
doing or not doing X, then by the PRAGMATICS of natural language I'm 
NOT supposed to juxtapose the two things -- even though both 
syntactically and semantically it's perfectly correct to do so.

Network protocol specs, programming language, libraries, etc, have 
pragmatics, too.  They're way harder to formalize, but that doesn't 
mean they can be blithely ignored in the real world.

Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly 
specified as NOT NULL.

But you should ONLY do so when the information is REALLY missing, NOT 
when you've lost it along the way because you've implemented 
adapter-chain transitivity: dropping information which you COULD have 
preserved with a bit more care (==without transitivity) is a violation 
of PRAGMATICS, of the BEST-EFFORT implication, just as it would be to 
drop packets once in a while in a TCP/IP stack due to some silly 
programming bug which was passed silently.

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 20:48, Phillip J. Eby wrote:
   ...
I'd rather not assume that class inheritance implies substitutability,
Hm, you should take that up with Alex then, since that is what his 
current PEP 246 draft does.  :)  Actually, the earlier drafts did that 
too, so I'm not sure why you want to change this now.

What I've actually suggested here actually allows for 
inheritance=substitutability as the default, but also makes it 
trivially changeable for any given inheritance hierarchy by overriding 
__conform__ at the base of that hierarchy, and without introducing a 
special exception class to do it.
The base of the hierarchy has no idea of which subclasses follow or 
break Liskov subtitutability.  It's just silly to site the check there. 
 Moreover, having to change the base class is more invasive than being 
able to do it in the derived class: typically the author of the derived 
class is taking the base class from some library and does not want to 
change that library -- changing the derived class is not ideal, but 
still way better.

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 09:23 PM 1/11/05 +0100, Alex Martelli wrote:
Is the concept of *PRAGMATICS* so deucedly HARD for all of your eggheads?!
Hmm.  Pot, meet kettle.  :)

Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly 
specified as NOT NULL.

But you should ONLY do so when the information is REALLY missing, NOT when 
you've lost it along the way because you've implemented adapter-chain 
transitivity: dropping information which you COULD have preserved with a 
bit more care (==without transitivity) is a violation of PRAGMATICS, of 
the BEST-EFFORT implication, just as it would be to drop packets once in a 
while in a TCP/IP stack due to some silly programming bug which was passed 
silently.
This is again a misleading analogy.  You are comparing end-to-end with 
point-to-point.  I am saying that if you have a point-to-point connection 
that drops all packets of a particular kind, you should not put it into 
your network, unless you know that an alternate route exists that can 
ensure those packets get through.  Otherwise, you are breaking the network.

Thus, I am saying that PRAGMATICALLY, it is silly to create a cable that 
drops all ACK packets, for example, and then plug it into your 
network.  And especially, it's silly to turn around that as a reason that 
one should only use end-to-end leased lines, because that packet forwarding 
business is dangerously unreliable!

As far as I can tell, you are arguing that you should never use packet 
forwarding for communication, because somebody might have a router 
somewhere that drops packets.  While I am arguing that if a router is known 
to drop packets incorrectly, the router is broken and should be removed 
from the network, or else bypassed via another route.  And, in the cases 
where you have a "leased line" direct from point A to point B, your routers 
should be smart enough to use that route in place of forwarding from A to C 
to D to B, or whatever.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 09:10 PM 1/11/05 +0100, Alex Martelli wrote:
On 2005 Jan 11, at 20:48, Phillip J. Eby wrote:
   ...
I'd rather not assume that class inheritance implies substitutability,
Hm, you should take that up with Alex then, since that is what his 
current PEP 246 draft does.  :)  Actually, the earlier drafts did that 
too, so I'm not sure why you want to change this now.

What I've actually suggested here actually allows for 
inheritance=substitutability as the default, but also makes it trivially 
changeable for any given inheritance hierarchy by overriding __conform__ 
at the base of that hierarchy, and without introducing a special 
exception class to do it.
The base of the hierarchy has no idea of which subclasses follow or break 
Liskov subtitutability.  It's just silly to site the check 
there.  Moreover, having to change the base class is more invasive than 
being able to do it in the derived class: typically the author of the 
derived class is taking the base class from some library and does not want 
to change that library -- changing the derived class is not ideal, but 
still way better.
Stop; you're responding to something I didn't propose!  (Maybe you're 
reading these posts in reverse order, and haven't seen the actual proposal 
yet?)

Clark said he didn't want to assume substitutability; I was pointing out 
that he could choose to not assume that, if he wished, by implementing an 
appropriate __conform__ at the base of his hierarchy.  This is entirely 
unrelated to deliberate Liskov violation, and is in any case not possible 
with your original proposal.  I don't agree with Clark's use case, but my 
proposal supports it as a possibility, and yours does not.

To implement a Liskov violation with my proposal, you do exactly the same 
as with your proposal, *except* that you can simply return None instead of 
raising an exception, and the logic for adapt() is more straightforward.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 23:20, Fredrik Lundh wrote:
back in Python 2.1 (and before), an object could define how copy.copy 
should
work simply by definining a __copy__ method.  here's the relevant 
portion:

...
try:
copierfunction = _copy_dispatch[type(x)]
except KeyError:
try:
copier = x.__copy__
except AttributeError:
raise error, \
  "un(shallow)copyable object of type %s" % type(x)
y = copier()
...
I recently discovered that this feature has disappeared in 2.3 and 
2.4.  in-
stead of looking for an instance method, the code now looks at the 
object's
type:
Hmmm, yes, we were discussing this general issue as part of the huge 
recent thread about pep 246.  In the new-style object model, special 
methods are supposed to be looked up on the type, not on the object; 
otherwise, having a class with special methods would be a problem -- 
are the methods meant to apply to the class object itself, or to its 
instances?

However, apparently, the code you quote is doing it wrong:
cls = type(x)
copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
copier = getattr(cls, "__copy__", None)
if copier:
return copier(x)
...because getattr is apparently the wrong way to go about it (e.g., it 
could get the '__copy__' from type(cls), which would be mistaken).  
Please see Armin Rigo's only recent post to Python-Dev for the way it 
should apparently be done instead -- assuming Armin is right (he 
generally is), there should be plenty of bugs in copy.py (ones that 
emerge when you're using custom metaclasses &c -- are you doing that?).

Still, if you're using an instance of an old-style class, the lookup in 
_copy_dispatch should be on types.InstanceType -- is that what you're 
trying to copy, an instance of an old-style class?


(copy.deepcopy still seems to be able to use __deepcopy__ hooks, 
though)
It starts with a peek into a dispatch dictionary for the type of the 
object, too, just like shallow copy does.  What's the type of what 
you're trying to copy?


is this a bug, or a feature of the revised copy/pickle design?   (the 
code in
copy_reg/copy/pickle might be among the more convoluted pieces of 
python
coding that I ever seen...  and what's that smiley doing in copy.py?)

and if it's a bug, does the fact that nobody reported this for 2.3 
indicate that
I'm the only one using this feature?  is there a better way to control 
copying
that I should use instead?
When I can, I use __getstate__ and __setstate__, simply because they 
seem clear and flexible to be (usable for copying, deep copying, 
pickling).  But that doesn't mean __copy__ or __deepcopy__ should be 
left broken, of course.

Although there are features of design intent here, it does appear to me 
there may be bugs too (if the getattr on the type is wrong); in this 
case it's worrisome, not just that nobody else reported problems, but 
also that the unit tests didn't catch them...:-(

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 23:39, Phillip J. Eby wrote:
   ...
cls = type(x)
copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
   ...
this a bug, or a feature of the revised copy/pickle design?
Looks like a bug to me; it breaks the behavior of classic classes, 
since type(classicInstance) returns InstanceType.
It doesn't, because types.InstanceType is a key in _copy_dispatch and 
gets a function that implements old-style classe behavior.

However, it also looks like it might have been introduced to fix the 
possibility that calling '__copy__' on a new-style class with a custom 
metaclass would result in ending up with an unbound method.  (Similar 
to the "metaconfusion" issue being recently discussed for PEP 246.)

ISTM the way to fix both issues is to switch to using x.__class__ in 
preference to type(x) to retrieve the __copy__ method from, although 
this still allows for metaconfusion at higher metaclass levels.
What "both issues"?  There's only one issue, it seems to me -- one of 
metaconfusion.

Besides, getattr(x.__class__, '__copy__') would not give backwards 
compatibility if x is an old-style instance -- it would miss the 
per-instance x.__copy__ if any.  Fortunately, _copy_dispatch deals with 
that.  So changing from type(x) to x.__class__ seems useless.

Maybe we need a getclassattr to deal with this issue, since I gather 
from Armin's post that this problem has popped up other places besides 
here and PEP 246.
Apparently we do: a bug in a reference implementation in a draft PEP is 
one thing, one that lives so long in a key module of the standard 
library is quite another.

(Follow-up: Guido's checkin comment for the change suggests it was 
actually done as a performance enhancement while adding a related 
feature (copy_reg integration), rather than as a fix for possible 
metaconfusion, even though it also has that effect.)
OK, but if Armin is correct about the code in the reference 
implementation of pep 246, and I think he is, this is still a bug in 
copy.py (though probably not the specific one that bit /f).

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 23:58, Guido van Rossum wrote:
   ...
cls = type(x)
copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
   ...
is this a bug, or a feature of the revised copy/pickle design?
[Phillip]
Looks like a bug to me; it breaks the behavior of classic classes, 
since
type(classicInstance) returns InstanceType.
I'm not so sure. I can't seem to break this for classic classes.
You can't, _copy_dispatch deals with those.
The only thing this intends to break, and then only for new-style
classes, is the ability to have __copy__ be an instance variable
(whose value should be a callable without arguments) -- it must be a
method on the class. This is the same thing that I've done for all
built-in operations (__add__, __getitem__ etc.).
And a wonderful idea it is.
However, it also looks like it might have been introduced to fix the
possibility that calling '__copy__' on a new-style class with a custom
metaclass would result in ending up with an unbound method.  (Similar 
to
the "metaconfusion" issue being recently discussed for PEP 246.)
Sorry, my head just exploded. :-(
I think I did this change (for all slots) to make the operations more
efficient by avoiding dict lookups. It does have the desirable
property of not confusing a class's attributes with its metaclass's
attributes, but only as long as you use the operation's native syntax
(e.g. x[y]) rather than the nominally "equivalent" method call (e.g.
x.__getitem__(y)).
Unfortunately, we do have a problem with the code in copy.py:
class MetaCopyableClass(type):
def __copy__(cls):
""" code to copy CLASSES of this metaclass """
# etc, etc, snipped
class CopyableClass:
__metaclass__ = MetaCopyableClass
# rest of class snipped
x = CopyableClass()
import copy
y = copy.copy(x)
kallisti:/tmp alex$ python x.py
Traceback (most recent call last):
  File "x.py", line 14, in ?
y = copy.copy(x)
  File "/usr/local/lib/python2.4/copy.py", line 79, in copy
return copier(x)
TypeError: __copy__() takes exactly 1 argument (2 given)
kallisti:/tmp alex$
See?  copy.copy(x) ends up using MetaCopyableClass.__copy__ -- because 
of a getattr on CopyableClass for '__copy__', which gets the 
BOUND-METHOD defined in the metaclass, with im_self being 
CopyableClass.

I had exactly the same metabug in the pep 246 reference implementation, 
Armin Rigo showed how to fix it in his only recent post.

Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Re: PEP 246: LiskovViolation as a name

2005-01-11 Thread David Ascher
Michael Chermside wrote:
David Ascher writes:
Terminology point: I know that LiskovViolation is technically correct,
but I'd really prefer it if exception names (which are sometimes all
users get to see) were more informative for people w/o deep technical
background.  Would that be possible?

I don't see how. Googling on Liskov immediately brings up clear
and understandable descriptions of the principle that's being violated.
I can't imagine summarizing the issue more concisely than that! What
would you suggest? Including better explanations in the documentation
is a must, but "LiskovViolation" in the exception name seems unbeatably
clear and concise.
Clearly, I disagree.
My point is that it'd be nice if we could come up with an exception name 
which could be grokkable without requiring 1) Google, 2) relatively 
high-level understanding of type theory.

Googling on Liskov brings up things like:
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple
"""What is wanted here is something like the following substitution 
property: If for each object o1 of type S there is an object o2 of type 
T such that for all programs P defined in terms of T, the behavior of P 
is unchanged when o1 is substituted for o2 then S is a subtype of T." - 
BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 
(May, 1988)."""

If you think that that is clear and understandable to the majority of 
the Python community, you clearly have a different perspective on that 
community.  I have (almost) no doubt that all Python-dev'ers understand 
it, but maybe we should ask someone like Anna Ravenscroft or Mark Lutz 
if they thinks it'd be appropriate from a novice user's POV.  I'm quite 
sure that the experts could understand a more pedestrian name, and quite 
sure that the reverse isn't true.

I also think that the term "violation" isn't necessarily the best word 
to add to the Python namespace, when error or exception would do just fine.

In addition, to say that it's unbeatably clear without a discussion of 
alternatives (or if I've missed it, please let me know) seems weird.

The point is broader, though -- when I get my turn in the time machine, 
I'll lobby for replacing NameError with UndefinedVariable or something 
similar (or more useful still).  The former is confusing to novices, and 
while it can be learned, that's yet another bit of learning which is, 
IMO, unnecessary, even though it may be technically more correct.

--david ascher
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name

2005-01-11 Thread Guido van Rossum
> My point is that it'd be nice if we could come up with an exception name
> which could be grokkable without requiring 1) Google, 2) relatively
> high-level understanding of type theory.

How about SubstitutabilityError?

> The point is broader, though -- when I get my turn in the time machine,
> I'll lobby for replacing NameError with UndefinedVariable or something
> similar (or more useful still).  The former is confusing to novices, and
> while it can be learned, that's yet another bit of learning which is,
> IMO, unnecessary, even though it may be technically more correct.

We did that for UnboundLocalError, which subclasses NameError. Perhaps
we can rename NameError to UnboundVariableError (and add NameError as
an alias for b/w compat).

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name

2005-01-11 Thread David Ascher
Guido van Rossum wrote:
My point is that it'd be nice if we could come up with an exception name
which could be grokkable without requiring 1) Google, 2) relatively
high-level understanding of type theory.

How about SubstitutabilityError?
That would be far, far better, yes.
We did that for UnboundLocalError, which subclasses NameError. Perhaps
we can rename NameError to UnboundVariableError (and add NameError as
an alias for b/w compat).
Sure, although (and here I'm pushing it, I know, and I should have 
argued it way back then), the notion of 'unbound' is possibly too 
low-level still.  'Unknown' would probably carry much more meaning to 
those people who most need it.

But yes, you're catching my drift.
--david
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Phillip J. Eby
At 11:56 PM 1/11/05 +0100, Alex Martelli wrote:
What "both issues"?  There's only one issue, it seems to me -- one of 
metaconfusion.
I was relying on Fredrik's report of a problem with the code; that is the 
other "issue" I referred to.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Phillip J. Eby
At 11:20 PM 1/11/05 +0100, Fredrik Lundh wrote:
I recently discovered that this feature has disappeared in 2.3 and 2.4.  in-
stead of looking for an instance method, the code now looks at the object's
type:
...
cls = type(x)
copier = _copy_dispatch.get(cls)
if copier:
return copier(x)
copier = getattr(cls, "__copy__", None)
if copier:
return copier(x)
...
(copy.deepcopy still seems to be able to use __deepcopy__ hooks, though)
is this a bug, or a feature of the revised copy/pickle design?
Looks like a bug to me; it breaks the behavior of classic classes, since 
type(classicInstance) returns InstanceType.

However, it also looks like it might have been introduced to fix the 
possibility that calling '__copy__' on a new-style class with a custom 
metaclass would result in ending up with an unbound method.  (Similar to 
the "metaconfusion" issue being recently discussed for PEP 246.)

ISTM the way to fix both issues is to switch to using x.__class__ in 
preference to type(x) to retrieve the __copy__ method from, although this 
still allows for metaconfusion at higher metaclass levels.

Maybe we need a getclassattr to deal with this issue, since I gather from 
Armin's post that this problem has popped up other places besides here and 
PEP 246.

(Follow-up: Guido's checkin comment for the change suggests it was actually 
done as a performance enhancement while adding a related feature (copy_reg 
integration), rather than as a fix for possible metaconfusion, even though 
it also has that effect.)

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Alex Martelli
On 2005 Jan 11, at 22:08, Phillip J. Eby wrote:
   ...
Yes, you're ALLOWED to stuff with NULL any field that isn't 
explicitly specified as NOT NULL.

But you should ONLY do so when the information is REALLY missing, NOT 
when you've lost it along the way because you've implemented 
adapter-chain transitivity: dropping information which you COULD have 
preserved with a bit more care (==without transitivity) is a 
violation of PRAGMATICS, of the BEST-EFFORT implication, just as it 
would be to drop packets once in a while in a TCP/IP stack due to 
some silly programming bug which was passed silently.
This is again a misleading analogy.  You are comparing end-to-end with 
point-to-point.  I am saying that if you have a point-to-point 
connection that drops all packets of a particular kind, you should not 
put it into your network, unless you know that an alternate route 
exists that can ensure those packets get through.  Otherwise, you are 
breaking the network.
But adaptation is not transmission!  It's PERFECTLY acceptable for an 
adapter to facade: to show LESS information in the adapted object than 
was in the original.  It's PERFECTLY acceptable for an adapter to say 
"this piece information is not known" when it's adapting an object for 
which that information, indeed, is not known.  It's only CONJOINING the 
two perfectly acceptable adapters, as transitivity by adapter chain 
would do automatically, that you end up with a situation that is 
pragmatically undesirable: asserting that some piece of information is 
not known, when the information IS indeed available -- just not by the 
route automatically taken by the transitivity-system.

What happened here is not that either of the adapters registered is 
wrong: each does its job in the best way it can.  The programming 
error, which transitivity hides (degrading the quality of information 
resulting from the system -- a subtle kind of degradation that will be 
VERY hard to unearth), is simply that the programmer forgot to register 
the direct adapter.  Without transitivity, the programmer's mistake 
emerges easily and immediately; transitivity hides the mistake.

By imposing transitivity, you're essentially asserting that, if a 
programmer forgets to code and register an A -> C direct adapter, this 
is never a problem, as long as A -> B and B -> C adapters are 
registered, because A -> B -> C will give results just as good as the 
direct A -> C would have, so there's absolutely no reason to trouble 
the programmer about the trivial detail that transitivity is being 
used.

At the same time, if I understand correctly, you're ALSO saying that if 
two other adapters exist, A -> Z and Z -> C, *THEN* it's an error, 
because you don't know when adapting A -> C whether to go via B or via 
Z.  Well, if you consistently believe what I state in the previous 
paragraph, then this is just weird: since you're implicitly asserting 
that any old A->?->C transitive adaptation is just as good as a direct 
A->C, why should you worry about there being more than one such 2-step 
adaptation available?  Roll the dice to pick one and just proceed.

Please note that in the last paragraph I'm mostly trying to "reason by 
absurd": I do NOT believe one can sensibly assert in the general case 
that A->?->C is just as good as A->C, without imposing FAR stronger 
constraints on adaptation that we possibly can (QI gets away with it 
because, designed from scratch, it can and does impose such 
constraints, essentially that all interfaces "belong" to ONE single 
object -- no independent 3rd party adaptation, which may be a bigger 
loss than the constraints gain, actually).

I'm willing to compromise to the extent of letting any given adaptation 
somehow STATE, EXPLICITLY, "this adaptation is lossless and perfect, 
and can be used as a part of transitive chains of adaptation without 
any cost whatsoever".  If we do that, though, the adaptation system 
should trust this assertion, so if there are two possibilities of equal 
minimal length, such as A->B->C or A->Z->C, with all the steps being 
declared lossless and perfect, then it SHOULD just pick one by whatever 
criterion, since both will be equally perfect anyway -- so maybe my 
reasoning by absurd wasn't totally absurd after all;-).

Would this compromise be acceptable to you?
Alex
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Guido van Rossum
[Fredrik]
> >I recently discovered that this feature has disappeared in 2.3 and 2.4.  in-
> >stead of looking for an instance method, the code now looks at the object's
> >type:
> >
> > ...
> >
> > cls = type(x)
> >
> > copier = _copy_dispatch.get(cls)
> > if copier:
> > return copier(x)
> >
> > copier = getattr(cls, "__copy__", None)
> > if copier:
> > return copier(x)
> >
> > ...
> >
> >(copy.deepcopy still seems to be able to use __deepcopy__ hooks, though)
> >
> >is this a bug, or a feature of the revised copy/pickle design?

[Phillip]
> Looks like a bug to me; it breaks the behavior of classic classes, since
> type(classicInstance) returns InstanceType.

I'm not so sure. I can't seem to break this for classic classes.

The only thing this intends to break, and then only for new-style
classes, is the ability to have __copy__ be an instance variable
(whose value should be a callable without arguments) -- it must be a
method on the class. This is the same thing that I've done for all
built-in operations (__add__, __getitem__ etc.).

> However, it also looks like it might have been introduced to fix the
> possibility that calling '__copy__' on a new-style class with a custom
> metaclass would result in ending up with an unbound method.  (Similar to
> the "metaconfusion" issue being recently discussed for PEP 246.)

Sorry, my head just exploded. :-(

I think I did this change (for all slots) to make the operations more
efficient by avoiding dict lookups. It does have the desirable
property of not confusing a class's attributes with its metaclass's
attributes, but only as long as you use the operation's native syntax
(e.g. x[y]) rather than the nominally "equivalent" method call (e.g.
x.__getitem__(y)).

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Clark C. Evans
On Tue, Jan 11, 2005 at 03:30:19PM -0500, Phillip J. Eby wrote:
| Clark said he didn't want to assume substitutability; I was pointing out 
| that he could choose to not assume that, if he wished, by implementing an 
| appropriate __conform__ at the base of his hierarchy. 

Oh, that's sufficient.  If someone making a base class wants to assert
that derived classes should check compliance (rather than having it
automagic), then they can do this.  Good enough!

| I don't agree with Clark's use case, but my 
| proposal supports it as a possibility, and yours does not.

It was a straw-man; and I admit, not a particularly compelling one.

| To implement a Liskov violation with my proposal, you do exactly the same 
| as with your proposal, *except* that you can simply return None instead 
| of raising an exception, and the logic for adapt() is more 
| straightforward.

I think I prefer just returning None rather than raising a
specific exception.  The semantics are different: None implies that
other adaptation mechanisms (like a registry) could be tried, while
LiskovException implies that processing halts and no further 
adaptation techniques are to be used.  In this case, None is 
the better choice for this particular case since it would enable
third-parties to register a wrapper.

Overall, I think both you and Alex are now proposing essentially
the same thing... no?

Best,

Clark

-- 
Clark C. Evans  Prometheus Research, LLC.
http://www.prometheusresearch.com/
o   office: +1.203.777.2550 
  ~/ ,  mobile: +1.203.444.0557 
 //
((   Prometheus Research: Transforming Data Into Knowledge
 \\  ,
   \/- Research Exchange Database
   /\- Survey & Assessment Technologies
   ` \   - Software Tools for Researchers
~ *
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Phillip J. Eby
At 02:58 PM 1/11/05 -0800, Guido van Rossum wrote:
[Phillip]
> Looks like a bug to me; it breaks the behavior of classic classes, since
> type(classicInstance) returns InstanceType.
I'm not so sure. I can't seem to break this for classic classes.
Sorry; I was extrapolating from what I thought was Fredrik's description of 
this behavior as a bug, and examining of the history of the code that he 
referenced.  I saw that the current version of that code had evolved 
directly from a version that was retrieving instance.__copy__; I therefore 
assumed that the loss-of-feature Fredrik was reporting was that.

That is, I thought that the problem he was experiencing was that classic 
classes no longer supported __copy__ because this code had changed.  I 
guess I should have looked at other lines of code besides the ones he 
pointed out; sorry about that.  :(


The only thing this intends to break, and then only for new-style
classes, is the ability to have __copy__ be an instance variable
(whose value should be a callable without arguments) -- it must be a
method on the class. This is the same thing that I've done for all
built-in operations (__add__, __getitem__ etc.).
Presumably, this is the actual feature loss that Fredrik's describing; i.e. 
lack of per-instance __copy__ on new-style classes.  That would make more 
sense.


> However, it also looks like it might have been introduced to fix the
> possibility that calling '__copy__' on a new-style class with a custom
> metaclass would result in ending up with an unbound method.  (Similar to
> the "metaconfusion" issue being recently discussed for PEP 246.)
Sorry, my head just exploded. :-(
The issue is that for special attributes (like __copy__, __conform__, etc.) 
that do not have a corresponding type slot, using getattr() is not 
sufficient to obtain slot-like behavior.  This is because 
'aType.__special__' may refer to a __special__ intended for *instances* of 
'aType', instead of the __special__ for aType.

As Armin points out, the only way to fully emulate type slot behavior for 
unslotted special attributes is to perform a search of the __dict__ of each 
type in the MRO of the type of the object for which you wish to obtain the 
special attribute.

So, in this specific case, __copy__ does not have a type slot, so it is 
impossible using getattr (or simple attribute access) to guarantee that you 
are retrieving the correct version of __copy__ in the presence of metaclasses.

This is what Alex and I dubbed "metaconfusion" in discussion of the same 
issue for PEP 246's __adapt__ and __conform__ methods; until they have 
tp_adapt and tp_conform slots, they can have this same problem.

Alex and I also just speculated that perhaps the stdlib should include a 
function that can do this, so that stdlib modules that define unslotted 
special attributes (such as __copy__) can ensure they work correctly in the 
presence of metaclasses.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name

2005-01-11 Thread David Ascher
Guido van Rossum wrote:
The point is broader, though -- when I get my turn in the time machine,
I'll lobby for replacing NameError with UndefinedVariable or something
Strange, my blog reading just hit upon
http://blogs.zdnet.com/open-source/index.php?p=93
...
"Perhaps as open source developers are making their resolutions for 
2005, they could add human-readable error codes to their list?
"

:-)
--david
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 06:38 PM 1/11/05 -0500, Clark C. Evans wrote:
| To implement a Liskov violation with my proposal, you do exactly the same
| as with your proposal, *except* that you can simply return None instead
| of raising an exception, and the logic for adapt() is more
| straightforward.
I think I prefer just returning None rather than raising a
specific exception.  The semantics are different: None implies that
other adaptation mechanisms (like a registry) could be tried, while
LiskovException implies that processing halts and no further
adaptation techniques are to be used.  In this case, None is
the better choice for this particular case since it would enable
third-parties to register a wrapper.
Overall, I think both you and Alex are now proposing essentially
the same thing... no?
Yes; I'm just proposing shuffling the invocation of things around a bit in 
order to avoid the need for an exception, and in the process increasing the 
number of possible customizations a bit.

Not that I care about those customizations as such; I just would like to 
simplify the protocol.  I suppose there's some educational benefit in 
making somebody explicitly declare that they're a Liskov violator, but it 
seems that if we're going to support it, it should be simple.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] Re: [Csv] csv module TODO list

2005-01-11 Thread Raymond Hettinger
Would the csv module be a good place to add a DBF reader and writer?  

Dbase's dbf file format is one of the oldest, simplest and more common
database interchange formats.   It can be a good alternative to CSV as a
means of sharing data with pre-existing, non-python apps.

On the plus side, it has a precise spec, can preserve numeric and date
types, has guaranteed round-trip equivalence, and does not have weird
escape rules.  On the minus side, strings are limited to ASCII without
NULs and the fields are fixed length.

I've posted a draft on ASPN.  It interoperates well with the rest of the
CSV module because it also accepts/returns a list of fieldnames and a
sequence of records.

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/362715



Raymond Hettinger

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] copy confusion

2005-01-11 Thread Fredrik Lundh
back in Python 2.1 (and before), an object could define how copy.copy should
work simply by definining a __copy__ method.  here's the relevant portion:

...
try:
copierfunction = _copy_dispatch[type(x)]
except KeyError:
try:
copier = x.__copy__
except AttributeError:
raise error, \
  "un(shallow)copyable object of type %s" % type(x)
y = copier()
...

I recently discovered that this feature has disappeared in 2.3 and 2.4.  in-
stead of looking for an instance method, the code now looks at the object's
type:

...

cls = type(x)

copier = _copy_dispatch.get(cls)
if copier:
return copier(x)

copier = getattr(cls, "__copy__", None)
if copier:
return copier(x)

...

(copy.deepcopy still seems to be able to use __deepcopy__ hooks, though)

is this a bug, or a feature of the revised copy/pickle design?   (the code in
copy_reg/copy/pickle might be among the more convoluted pieces of python
coding that I ever seen...  and what's that smiley doing in copy.py?)

and if it's a bug, does the fact that nobody reported this for 2.3 indicate that
I'm the only one using this feature?  is there a better way to control copying
that I should use instead?

 



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Re: copy confusion

2005-01-11 Thread Fredrik Lundh
Guido van Rossum wrote:

> The only thing this intends to break /.../

it breaks classic C types:

>>> import cElementTree
>>> x = cElementTree.Element("tag")
>>> x

>>> x.__copy__

>>> x.__copy__()

>>> import copy
>>> y = copy.copy(x)
Traceback (most recent call last):
  File "", line 1, in ?
  File "C:\python24\lib\copy.py", line 93, in copy
raise Error("un(shallow)copyable object of type %s" % cls)
copy.Error: un(shallow)copyable object of type 
>>> dir(x)
['__copy__', '__deepcopy__', 'append', 'clear', 'find', 'findall', 'findtext',
'get', 'getchildren', 'getiterator', 'insert', 'items', 'keys', 'makeelement', 
'set']
>>> dir(type(x))
['__class__', '__delattr__', '__delitem__', '__delslice__', '__doc__',
'__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__',
'__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__setitem__', '__setslice__', '__str__']

(and of course,  custom C types is the only case where I've ever used
__copy__; the default behavior has worked just fine for all other cases)

for cElementTree, I've worked around this with an ugly __reduce__ hack,
but that doesn't feel right...

 



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Raymond Hettinger
> Thus, my argument is that an adapter like this should never be made
part
> of
> the adapter system, even if there's no transitivity.  However, if you
> agree
> that such an adapter shouldn't be implicit, then it logically follows
that
> there is no problem with allowing transitivity, except of course that
> people may sometimes break the rule.

At some point, the PEP should be extended to include a list of best
practices and anti-patterns for using adapters.  I don't find issues of
transitivity and implicit conversion to be immediately obvious.

Also, it is not clear to me how or if existing manual adaption practices
should change.  For example, if I need a file-like interface to a
string, I currently wrap it with StringIO.  How will that change it the
future?  By an explicit adapt/conform pair?  Or by strings knowing how
to conform to file-like requests?


Raymond Hettinger

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Re: [Csv] csv module TODO list

2005-01-11 Thread Andrew McNamara
>Would the csv module be a good place to add a DBF reader and writer?  

I would have thought it would make sense as it's own module (in the same
way that we have separate modules that present a common interface for
the different databases), or am I missing something?

I'd certainly like to see a DBF parser in python - reading and writing odd
file formats is bread-and-butter for us contractors... 8-)

-- 
Andrew McNamara, Senior Developer, Object Craft
http://www.object-craft.com.au/
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 12:33 AM 1/12/05 +0100, Alex Martelli wrote:
But adaptation is not transmission!  It's PERFECTLY acceptable for an 
adapter to facade: to show LESS information in the adapted object than was 
in the original.
It's also true that it's acceptable for a router to choose not to forward 
packets, e.g. for security reasons, QoS, etc.  My point was that you seem 
to be using this to conclude that multihop packet forwarding is a bad idea 
in the general case, and that's what doesn't make any sense to me.

More to the point, the error in your example isn't the filtering-out of 
information, it's the adding of a NULL back in.  If NULLs are questionable 
for the target interface, this is not in general a candidate for implicit 
adaptation IMO -- *whether or not transitivity is involved*.

Let's look at the reverse of the float-to-int case for a better 
example.  Should I be able to implicitly adapt a float to a Decimal?  No, 
because I might be making up precision that isn't there.  May I explicitly 
convert a float to a decimal, if I know what I'm doing?  Yes, of 
course.  Just don't expect Python to guess for you.

This is very much like your example; adding a NULL middle name seems to me 
almost exactly like going from float to Decimal with spurious 
precision.  If you know what you're doing, it's certainly allowable to do 
it explicitly, but Python should not do it implicitly.

Thus, my argument is that an adapter like this should never be made part of 
the adapter system, even if there's no transitivity.  However, if you agree 
that such an adapter shouldn't be implicit, then it logically follows that 
there is no problem with allowing transitivity, except of course that 
people may sometimes break the rule.

However, I think we actually have an opportunity now to actually codify 
sensible adaptation practices, such that the violations will be 
infrequent.  It's also possible that we may be able to define some sort of 
restricted implicitness so that somebody making a noisy adapter can 
implicitly adapt in a limited context.


What happened here is not that either of the adapters registered is wrong: 
each does its job in the best way it can.  The programming error, which 
transitivity hides (degrading the quality of information resulting from 
the system -- a subtle kind of degradation that will be VERY hard to 
unearth), is simply that the programmer forgot to register the direct 
adapter.  Without transitivity, the programmer's mistake emerges easily 
and immediately; transitivity hides the mistake.
Where we differ is that I believe that if the signal degradation over a 
path isn't acceptable, it shouldn't be made an implicit part of the 
network; it should be an explicitly forced route instead.

Note by the way, that the signal degradation in your example comes from a 
broken adapter: it isn't valid to make up data if you want real data.  It's 
PRAGMATIC, as you say, to make up the data when you don't have a choice, 
but this does not mean it should be AUTOMATIC.

So, we both believe in restricting the automatic and implicit nature of 
adaptation.  The difference is that I'm saying you should be explicit when 
you do something questionable, and you are saying you should be explicit 
when you're doing something that is *not*.  Perhaps as you previously 
suggested, this really is the aspect where we need the BDFL to be the 
tiebreaker.


At the same time, if I understand correctly, you're ALSO saying that if 
two other adapters exist, A -> Z and Z -> C, *THEN* it's an error, because 
you don't know when adapting A -> C whether to go via B or via Z.  Well, 
if you consistently believe what I state in the previous paragraph, then 
this is just weird: since you're implicitly asserting that any old A->?->C 
transitive adaptation is just as good as a direct A->C, why should you 
worry about there being more than one such 2-step adaptation available?
Because such ambiguities are usually an indication of some *other* error, 
often in the area of interface inheritance transitivity; they rarely occur 
as a direct result of implementing two versions of the same adapter (at 
least in my experience).


I'm willing to compromise to the extent of letting any given adaptation 
somehow STATE, EXPLICITLY, "this adaptation is lossless and perfect, and 
can be used as a part of transitive chains of adaptation without any cost 
whatsoever".  If we do that, though, the adaptation system should trust 
this assertion, so if there are two possibilities of equal minimal length, 
such as A->B->C or A->Z->C, with all the steps being declared lossless and 
perfect, then it SHOULD just pick one by whatever criterion, since both 
will be equally perfect anyway -- so maybe my reasoning by absurd wasn't 
totally absurd after all;-).
Here's the part I don't think you're seeing: interface inheritance 
transitivity has this *exact* same problem, and it's *far* easier to 
stumble into it, assuming you don't start out by declaring adapters tha

[Python-Dev] PEP 246, redux

2005-01-11 Thread Roeland Rengelink
I'm trying to understand the relation between Guido's posts on optional 
 static typing and PEP 245 (interfaces) and 246 (adaptation). I have a 
 couple of questions

PEP 245 proposes to introduce a fundamental distinction between type and 
 interface. However, 245 only introduces a syntax for interfaces, and 
says very little about the semantics of interfaces. (Basically only that 
 if X implements Y then implements(X, Y) will return True). The 
semantics of interfaces are currently only implied by PEP 246, and by 
Guido's  posts referring to 246.

Unfortunately PEP 246 explicitly refuses to decide that protocols are 
245-style interfaces. Therefore, it is not clear to me how acceptance of 
 245 would impact on 246?  Specifically, what would be the difference 
between:

x = adapt(obj, a_245_style_interface)
x = adapt(obj, a_protocol_type)
and, if there is no difference, what would the use-case of interfaces be?
Put another way: explicit interfaces and adaptation based typing seem to 
 be about introducing rigor (dynamic, not static) to Python. Yet, PEP 
245 and 246 seems to go out of their way to give interfaces and 
adaptation as little baggage as possible. So, where is the rigor going 
to come from?

On the one hand this seems very Pythonic - introduce a new feature with 
as little baggage as possible, and see where it evolves from there. Let 
the rigor flow, not from the restrictions of the language, but from the 
 expressive power of the language.

On the other hand: why not, at least:
- explore in 245 how the semantics of interfaces might introduce rigor 
into the language. It would be particularly illuminating to find out in 
what way implementing an interface differs from deriving from an ABC 
and  in what way an interface hierarchy differs semantically from a 
hierarchy  of ABCs

- rewrite 246 under the assumption that 245 (including semantics) has 
been accepted

I would volunteer, but, for those of you who hadn't noticed yet, I don't 
know what I'm talking about.

Cheers,
Roeland Rengelink

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


RE: [Python-Dev] PEP 246, redux

2005-01-11 Thread Phillip J. Eby
At 07:52 PM 1/11/05 -0500, Raymond Hettinger wrote:
Also, it is not clear to me how or if existing manual adaption practices
should change.  For example, if I need a file-like interface to a
string, I currently wrap it with StringIO.  How will that change it the
future?  By an explicit adapt/conform pair?  Or by strings knowing how
to conform to file-like requests?
The goal here is to be able to specify that a function parameter takes, 
e.g. a "readable stream", and that you should be able to either explicitly 
wrap in a StringIO to satisfy this, or *possibly* that you be able to just 
pass a string and have it work automatically.

If the latter is the case, there are a variety of possible ways it might 
work.  str.__conform__ might recognize the "readable stream" interface, or 
the __adapt__ method of the "readable stream" interface could recognize 
'str'.  Or, Alex's new proposed global type registry might contain an entry 
for 'str,readableStream'.  Which of these is the preferred scenario very 
much depends on a lot of things, like who defined the "readable stream" 
interface, and whether anybody has registered an adapter for it!

PyProtocols tries to answer this question by allowing you to register 
adapters with interfaces, and then the interface's __adapt__ method will do 
the actual adaptation.  Zope does something similar, at least in that it 
uses the interface's __adapt__ method, but that method actually uses a 
global registry.

Neither PyProtocols nor Zope make much use of actually implementing 
hand-coded __conform__ or __adapt__ methods, as it's too much trouble for 
something that's so inherently declarative anyway, and only the creator of 
the object class or the interface's type have any ability to define 
adapters that way.  Given that built-in types are often handy sources of 
adaptation (e.g. str-to-StringIO in your example), it isn't practical in 
present-day Python to add a __conform__ method to the str type!

Thus, in the general case it just seems easier to use a per-interface or 
global registry for most normal adaptation, rather than using 
__conform__.  However, having __conform__ exist is a nice "out" for 
implementing unusual custom requirements (like easy dynamic conformance), 
so I don't think it should be removed.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] copy confusion

2005-01-11 Thread Guido van Rossum
> Unfortunately, we do have a problem with the code in copy.py:
> 
> class MetaCopyableClass(type):
>  def __copy__(cls):
>  """ code to copy CLASSES of this metaclass """
>  # etc, etc, snipped
> 
> class CopyableClass:
>  __metaclass__ = MetaCopyableClass
>  # rest of class snipped
> 
> x = CopyableClass()
> 
> import copy
> y = copy.copy(x)
> 
> kallisti:/tmp alex$ python x.py
> Traceback (most recent call last):
>File "x.py", line 14, in ?
>  y = copy.copy(x)
>File "/usr/local/lib/python2.4/copy.py", line 79, in copy
>  return copier(x)
> TypeError: __copy__() takes exactly 1 argument (2 given)
> kallisti:/tmp alex$
> 
> See?  copy.copy(x) ends up using MetaCopyableClass.__copy__ -- because
> of a getattr on CopyableClass for '__copy__', which gets the
> BOUND-METHOD defined in the metaclass, with im_self being
> CopyableClass.
> 
> I had exactly the same metabug in the pep 246 reference implementation,
> Armin Rigo showed how to fix it in his only recent post.

Don't recall seeing that, but if you or he can fix this without
breaking other stuff, it's clear you should go ahead. (This worked in
2.2, FWIW; it broke in 2.3.)

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com