[Python-Dev] Re: str() vs format(): trivia question

2021-04-21 Thread Serhiy Storchaka
20.04.21 22:01, Guido van Rossum пише:
> So to be clear, that one user wants f"{Color.RED}" to return "1" and not
> " Color.RED" (or  something like that).

The user should write f"{int(Color.RED)}" or f"{Color.RED.value}".

I have also an idea to support of additional conversion characters, so
the use could write f"{Color.RED!i}". Opened a discussion for this on
Python-ideas.
https://mail.python.org/archives/list/python-id...@python.org/thread/3AALXB6A7EN6UY635MF5O2SFHZVFA5NM/


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/UB4PDYSREAEUXAEUVCIZQA4G5KJPFEVD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: str() vs format(): trivia question

2021-04-21 Thread Serhiy Storchaka
20.04.21 17:56, Ethan Furman пише:
> urllib.urlencode currently uses `str()` on its non-bytes objects before
> encoding the result.  This causes a compatibility break when integer
> module constants are converted to IntEnum, as `str(IntEnum.MEMBER)` no
> longer returns the integer representation; however, `format()` does
> still return the integer representation.
> 
> The fix is to add a separate branch to check if the argument is an Enum,
> and use the value if so -- but it got me wondering: in general, are
> there differences between calling str() vs calling format() on Python
> objects?

format() without format specifier and str() should return the same value
in general, otherwise it will confuse users. But str() for enum should
in general return a symbolic name, not the attached value which is an
implementation detail. This is the purpose of enums.

I think that __format__ should return the same as __str__ by default.
This can break some user code, but custom __str__ can break it as well.
Some breakage is inevitable when we convert some constants in the stdlib
to enums. If user want to get an integer representation of an enum
member, it should use IntEnum.MEMBER.value or int(IntEnum.MEMBER).

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/TGWLHZA7F6OW35IAGTQBLTAURRQMACCP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Sebastian Rittau

Am 20.04.2021 um 19:03 schrieb Mark Shannon:
PEP 544 supports structural typing, but to declare a structural type 
you must inherit from Protocol.

That smells a lot like nominal typing to me.


I'm not sure what inheriting from Protocol has to do with nominal 
typing, even though I would personally prefer to have a separate keyword 
for declaring protocols. But current typing philosophy is to prefer 
structural over nominal typing:


 * Use abstract types like "Iterable" or "Sequence" over concrete types
   list "list".
 * Use protocols instead of instances where it makes sense (although
   pragmatism very often means using an existing concrete class instead
   of defining a protocol).
 * We are slowly replacing typing.IO et al. with more restricted protocols.

Personally I think that the typing infrastructure should move even more 
towards structural typing than it does at the moment and there is 
certainly a lot of room to grow. But overall I feel that typing is 
moving towards allowing more duck typing than it does at the moment.


 - Sebastian

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4SDOHDJENVLNDZVJYZN47JSHWJMN4SHV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: [python-committers] PEP 563 and Python 3.10.

2021-04-21 Thread Anthony Baxter
While I have not been involved in the release process for like 15 years or
more, I would like to point out that breaking changes mean the distros are
less likely to ship them, and be less likely to trust updates.

Trying to get RH &c to stop shipping 1.5.2 was a huge effort.

Always, any time when you might need to break compat it's a huge risk.

On Wed, 21 Apr 2021, 4:58 am Thomas Wouters,  wrote:

>
> (Starting a new thread so as not to derail any of the ongoing discussions.)
>
> Thanks, everyone, for your thoughts on Python 3.10 and the impact of PEP
> 563 (postponed evaluation of annotations) becoming the default. The
> Steering Council has considered the issue carefully, along with many of the
> proposed alternatives and solutions, and we’ve decided that at this point,
> we simply can’t risk the compatibility breakage of PEP 563. We need to roll
> back the change that made stringified annotations the default, at least for
> 3.10. (Pablo is already working on this.)
>
> To be clear, we are not reverting PEP 563 itself. The future import will
> keep working like it did since Python 3.7. We’re delaying making PEP 563
> string-based annotations the default until Python 3.11. This will give us
> time to find a solution that works for everyone (or to find a feasible
> upgrade path for users who currently rely on evaluated annotations). Some
> considerations that led us to this decision:
>
>  - PEP 563’s default change is clearly too disruptive to downstream users
> and third-party libraries to happen right now. We can’t risk breaking even
> a small subset of the FastAPI/pydantic users, not to mention other uses of
> evaluated type annotations that we’re not aware of yet.
>  - PEP 563 provides no warning to users of the feature it’s disabling.
> Without that, we can’t expect users to be aware of the upcoming breakage.
> The lack of a warning was by design, and made sense in a world where type
> annotations were only consumed by static type checkers --- but that’s not
> actually the situation we’re in.  There are clearly existing real-world,
> run-time uses of type annotations that would be adversely affected by this
> change.
>  - Originally, PEP 563 was scheduled to take effect in Python 4, and this
> changed recently (after the discussion in the Language Summit of 2020).
> It's possible that third-party libraries and users didn’t plan to react in
> the current time frame as they were not aware of this change in timing.
>  - There isn’t enough time to properly discuss PEP 649 or any of the
> alternatives before the beta 1 deadline, and we really need to make sure we
> don’t compound errors here.  We need to look for a long term solution,
> which isn’t possible while still maintaining the release deadlines of
> Python 3.10.  That means we’re also deferring PEP 649 to Python 3.11.
>
> In the Steering Council’s unanimous opinion, rolling back the default flip
> for stringified annotations in Python 3.10 is the least disruptive of all
> the options.
>
> We need to continue discussing the issue and potential solutions, since
> this merely postpones the problem until 3.11. (For the record, postponing
> the change further is not off the table, either, for example if the final
> decision is to treat evaluated annotations as a deprecated feature, with
> warnings on use.)
>
> For what it’s worth, the SC is also considering what we can do to reduce
> the odds of something like this happening again, but that’s a separate
> consideration, and a multi-faceted one at that.
>
> For the Steering Council,
> Thomas.
> --
> Thomas Wouters 
>
> Hi! I'm an email virus! Think twice before sending your email to help me
> spread!
> ___
> python-committers mailing list -- python-committ...@python.org
> To unsubscribe send an email to python-committers-le...@python.org
> https://mail.python.org/mailman3/lists/python-committers.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-committ...@python.org/message/CLVXXPQ2T2LQ5MP2Y53VVQFCXYWQJHKZ/
> Code of Conduct: https://www.python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ULSWULZIBTYQ5GRBTLRQGNKQ525S7WJC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread srku...@mail.de
Removing two concepts and preserving semantics simplifies the matter for users. 
People need less to memorize and less to learn.

Or am I missing something here? Couldn’t we achieve our goal without these two 
new classes?

Splitting, wrapping and exception handling semantics are perfectly fine and 
serve their purposes. So, of course this still needs to be implemented.

> On 20. Apr 2021, at 23:26, Irit Katriel  wrote:
> 
> I don’t see what this simplifies. We still need to implement split, and to 
> worry about wrapping or not wrapping BaseExceptions and we still need to 
> define exception handling semantics (except/except*).
> 
> 
>> On 20 Apr 2021, at 22:12, srku...@mail.de wrote:
>> 
>> So, forgive me my relatively simple mental model about ExceptionGroup. I 
>> still try to create one for daily use.
>> 
>> As noted in the discussion, an EG provides a way to collect exceptions from 
>> different sources and raise them as a bundle. They have no apparent relation 
>> up until this point in time (for whatever reason they have been separate and 
>> for whatever reason they are bundled now). The result would be a tree graph 
>> in any case.
>> 
>> A usual datastructure for a tree is to store all child nodes at the parent 
>> node.
>> 
>> That was the idea behind the content of BaseException.__group__: it’s the 
>> list of child exceptions bundled at a specific point in time and raise as 
>> such a bundle. So all exceptions could become EGs with the additional 
>> semantics you‘ve described in the PEP.
>> 
>> Illustrative Example:
> bundle_exc.__group__
>> [IOError(123), RuntimerError(‘issue somewhere’)]
>> 
>> I was wondering what of the PEP could be removed to make it simpler and more 
>> acceptable/less confusing (also looking at reactions from Twitter etc.) and 
>> I found these additional classes to be a part of it. Additionally, I fail to 
>> see how to access these bundled exceptions in an easy manner like __cause__ 
>> and __context__. (As the PEP also referring to them). So, I removed the 
>> classes and added a regular attribute.
>> 
>> The reason I brought this up what the section “rejected ideas” didn’t showed 
>> anything in this direction (or I managed to missed that).
>> 
>> Sven
>> 
>>> 
 On 20. Apr 2021, at 22:05, Irit Katriel  wrote:
>>> 
>>> Hi Sven,
>>> 
>>> I don’t follow.  What would the value of __group__ be and how would it work?
>>> 
>>> Irit
>>> 
> On 20 Apr 2021, at 20:44, srku...@mail.de wrote:
 
 Hi Irit,
 reading this subthread specifically, I just got a wild idea and I couldn‘t 
 find any related information in the PEP:
 Why not extending BaseException by __group__ among __cause__ and 
 __context__?
 Would this reduce some of the added complexity and thus increase broader 
 acceptance?
 Cheers,
 Sven
>> 

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OD6IDT5HGDULGLVVQ2HF7WJXNQM7RA3K/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread Yury Selivanov
On Wed, Apr 21, 2021 at 11:50 AM srku...@mail.de  wrote:
>
> Removing two concepts and preserving semantics simplifies the matter for 
> users. People need less to memorize and less to learn.
>
> Or am I missing something here? Couldn’t we achieve our goal without these 
> two new classes?

No, we can't. What you are proposing would make it very hard for users
to understand at a glance if what you have in an innocently looking
`except Exception` is correct or not.  In my async/await code I'd have
to always check the `__group__` attribute to make sure it's not an
exception group in disguise.

So while you're "simplifying" the proposal by removing a couple of
types, you're complicating it in all other places. Besides, I don't
think that adding the ExceptionGroup type is a controversial idea that
needs any simplification.

Yury
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/IXHLXQYTEFPRC2GLFGAM6GHCYAAQG4DQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Christopher Barker
Thanks Mark for posting this. I know some of us are uneasy about the pace
of the typing train 

On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith  wrote:

> > If you guarded your code with `isinstance(foo, Sequence)` then I could
> > not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> > forced to use nominal typing; inheriting from Sequence, or explicitly
> > registering as a Sequence.
>
> You say this like it's a bad thing, but how is this avoidable, even in
> principle? Structural typing lets you check whether Foo is duck-shaped
> -- has appropriate attribute names, etc. But quacking like a duck is
> harder: you also have to implement the Sequence behavioral contract,
> and realistically the only way to know that is if the author of Foo
> tells you.
>

But that's not what duck typing is (at least to me :-) ) For a given
function, I need the passed in object to quack (and yes, I need that quack
to sound like a duck) -- but I usually don't care whether that object
waddles like a duck.

So yes, isinstance(obj, Sequence) is really the only way to know that obj
is a Sequence in every important way -- but if you only need it to do one
or two things like a Sequence, then you don't care.

And this is not uncommon -- I suspect it's very rare for a single function
to use most of the methods of a given ABC (or protocol, or whatever).

And a lot of the standard library works exactly this way. Two examples
(chosen arbitrarily, I just happen to have thought about how they work):

json.load() simply calls ``fp.read()``, and passes the result on down to
json.loads(). That's it -- no checking of anything.

If fp does not have a read() method, you get an AttributeError. If fp has a
read() method, but it returns something other than a string, then you get
some other Exception. And if it returns a string, but that string isn't
valid JSON, you get yet another kind of error.

In short, json.load(fp, ...) requires fp to have a read() method that
returns a valid JSON string. But it doesn't check, nor does it need to, if
it's getting an actual io.TextIOBase object. Is that the right one? I'm not
totally sure, which I kind of think makes my point -- I've been using
"file-like" objects for years (decades) without worrying about it.

Example 2:

The str.translate method takes:

"a mapping of Unicode ordinals to Unicode ordinals, strings, or None"

Ok, then you need to pass in a Mapping, yes? Well, no you don't. The docs
go on to say:

The table must implement lookup/indexing via __getitem__, for instance a
dictionary or list.

Ah -- so we don't need a Mapping -- we need anything indexable by an
integer that contains "ordinals, strings, or None". What the heck ABC could
we use for that?

The ABCs do have an already complex hierarchy of containers, but there is
no "Indexable", (quacks) and certainly no "indexable and returns these
particular things. (quacks a certain way). (maybe there's something in the
typing module that would work for static typing -- I have no idea).

I'm pretty sure this particular API was designed to accommodate the old py2
str.translate, which took a length-256 sequence, while also
accommodating full Unicode, which would have required a 2^32 length
sequence to do the same thing :-)

But again -- this is duck typing, built into the stdlib, and it works
just fine.

Granted, until PEP 563 (kind of) , there has been nothing that weakens or
disallows such duck typing -- those of us that want to write fully
duck-typed code can continue to do so.

But there is the "culture" of Python -- and it has been very much shifting
toward more typing -- A recent publication (sorry can't find it now -- my
google fu is failing me) examined code on PyPi and found a lot of type
hints -- many of which were apparently not being used with a static type
checker. So why were they there?

And I've seen a lot more isinstance(Some_ABC) code lately as well.

>From looking at the work of my beginning students, I can tell that they are
seeing examples out there that use more typing, to the point that they
think it's a best practice (or maybe even required?). Maybe it is -- but if
the community is moving that way, we should be honest about it.


> I'm not even sure that this *is* nominal typing. You could just as
> well argue that "the operation `isinstance(..., Sequence)` returns
> `True`" is just another of the behavioral constraints that are
> required to quack like a sequence.
>

I'm not sure of the definition of "nominal" typing -- but it absolutely is
NOT duck typing (As Luciano pointed out, Alex Martelli coined the term
Goose Typing for this).

The big distinction is whether we want to know if the object is a duck, or
if we only need it to do one or two things like a duck.

-CHB


-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Py

[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread Nathaniel Smith
On Tue, Apr 20, 2021 at 2:15 PM srku...@mail.de  wrote:
>
> So, forgive me my relatively simple mental model about ExceptionGroup. I 
> still try to create one for daily use.
>
> As noted in the discussion, an EG provides a way to collect exceptions from 
> different sources and raise them as a bundle. They have no apparent relation 
> up until this point in time (for whatever reason they have been separate and 
> for whatever reason they are bundled now). The result would be a tree graph 
> in any case.
>
> A usual datastructure for a tree is to store all child nodes at the parent 
> node.
>
> That was the idea behind the content of BaseException.__group__: it’s the 
> list of child exceptions bundled at a specific point in time and raise as 
> such a bundle. So all exceptions could become EGs with the additional 
> semantics you‘ve described in the PEP.
>
> Illustrative Example:
> >>> bundle_exc.__group__
> [IOError(123), RuntimerError(‘issue somewhere’)]
>
> I was wondering what of the PEP could be removed to make it simpler and more 
> acceptable/less confusing (also looking at reactions from Twitter etc.) and I 
> found these additional classes to be a part of it. Additionally, I fail to 
> see how to access these bundled exceptions in an easy manner like __cause__ 
> and __context__. (As the PEP also referring to them). So, I removed the 
> classes and added a regular attribute.

This seems more confusing to me too. Instead of having a single
ExceptionGroup class, you're suggesting that all exceptions should
effectively become ExceptionGroups. I know what
ExceptionGroup([ValueError]) means -- it means there was a ValueError,
and it got put in a group, so it should probably be handled the same
way as a ValueError. I have no idea what a KeyError([ValueError])
would mean. Is that a KeyError or a ValueError? Adding flexibility
doesn't necessarily make things simpler :-)

-n

-- 
Nathaniel J. Smith -- https://vorpus.org
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/F6LVP7CLQGIAZ2PI2SL6FN3VXF2MVY2M/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language

2021-04-21 Thread David Antonini
I think what Christopher says is fair. My question (with little understanding 
of the underlying infrastructure) is can we define a 'type' that communicates 
that? Something like 'object that implements .read', or '.upper and .__iter__ 
for a spring-like object's?

toonarmycaptain







 Original message 
From: python-dev-requ...@python.org
Date: 4/21/21 2:44 PM (GMT-06:00)
To: python-dev@python.org
Subject: Python-Dev Digest, Vol 213, Issue 128

Send Python-Dev mailing list submissions to
python-dev@python.org

To subscribe or unsubscribe via the World Wide Web, visit
https://mail.python.org/mailman3/lists/python-dev.python.org/
or, via email, send a message with subject or body 'help' to
python-dev-requ...@python.org

You can reach the person managing the list at
python-dev-ow...@python.org

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Python-Dev digest..."

Today's Topics:

   1. Re: PEP 654: Exception Groups and except* [REPOST]
  (srku...@mail.de)
   2. Re: PEP 654: Exception Groups and except* [REPOST]
  (Yury Selivanov)
   3. Re: Keeping Python a Duck Typed Language. (Christopher Barker)


--

Message: 1
Date: Wed, 21 Apr 2021 20:48:29 +0200
From: "srku...@mail.de" 
Subject: [Python-Dev] Re: PEP 654: Exception Groups and except*
[REPOST]
To: Irit Katriel 
Cc: Irit Katriel , python-dev
, Yury Selivanov 
Message-ID: <04512110-64b5-4ab3-ae54-ae6889c77...@mail.de>
Content-Type: text/plain; charset=utf-8

Removing two concepts and preserving semantics simplifies the matter for users. 
People need less to memorize and less to learn.

Or am I missing something here? Couldn’t we achieve our goal without these two 
new classes?

Splitting, wrapping and exception handling semantics are perfectly fine and 
serve their purposes. So, of course this still needs to be implemented.

> On 20. Apr 2021, at 23:26, Irit Katriel  wrote:
>
> I don’t see what this simplifies. We still need to implement split, and to 
> worry about wrapping or not wrapping BaseExceptions and we still need to 
> define exception handling semantics (except/except*).
>
>
>> On 20 Apr 2021, at 22:12, srku...@mail.de wrote:
>>
>> So, forgive me my relatively simple mental model about ExceptionGroup. I 
>> still try to create one for daily use.
>>
>> As noted in the discussion, an EG provides a way to collect exceptions from 
>> different sources and raise them as a bundle. They have no apparent relation 
>> up until this point in time (for whatever reason they have been separate and 
>> for whatever reason they are bundled now). The result would be a tree graph 
>> in any case.
>>
>> A usual datastructure for a tree is to store all child nodes at the parent 
>> node.
>>
>> That was the idea behind the content of BaseException.__group__: it’s the 
>> list of child exceptions bundled at a specific point in time and raise as 
>> such a bundle. So all exceptions could become EGs with the additional 
>> semantics you‘ve described in the PEP.
>>
>> Illustrative Example:
> bundle_exc.__group__
>> [IOError(123), RuntimerError(‘issue somewhere’)]
>>
>> I was wondering what of the PEP could be removed to make it simpler and more 
>> acceptable/less confusing (also looking at reactions from Twitter etc.) and 
>> I found these additional classes to be a part of it. Additionally, I fail to 
>> see how to access these bundled exceptions in an easy manner like __cause__ 
>> and __context__. (As the PEP also referring to them). So, I removed the 
>> classes and added a regular attribute.
>>
>> The reason I brought this up what the section “rejected ideas” didn’t showed 
>> anything in this direction (or I managed to missed that).
>>
>> Sven
>>
>>>
 On 20. Apr 2021, at 22:05, Irit Katriel  wrote:
>>>
>>> Hi Sven,
>>>
>>> I don’t follow.  What would the value of __group__ be and how would it work?
>>>
>>> Irit
>>>
> On 20 Apr 2021, at 20:44, srku...@mail.de wrote:
 
 Hi Irit,
 reading this subthread specifically, I just got a wild idea and I couldn‘t 
 find any related information in the PEP:
 Why not extending BaseException by __group__ among __cause__ and 
 __context__?
 Would this reduce some of the added complexity and thus increase broader 
 acceptance?
 Cheers,
 Sven
>>


--

Message: 2
Date: Wed, 21 Apr 2021 11:58:23 -0700
From: Yury Selivanov 
Subject: [Python-Dev] Re: PEP 654: Exception Groups and except*
[REPOST]
To: "srku...@mail.de" 
Cc: Irit Katriel , Irit Katriel
, python-dev , Yury
Selivanov 
Message-ID:

Content-Type: text/plain; charset="UTF-8"

On Wed, Apr 21, 2021 at 11:50 AM srku...@mail.de  wrote:
>
> Removing two concepts and preserving semantics simplifies the matter for 
> users. People need less to memorize and less to learn.
>
> Or am I mis

[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread Nathaniel Smith
On Tue, Apr 20, 2021 at 3:15 AM Irit Katriel  wrote:
> On Tue, Apr 20, 2021 at 2:48 AM Nathaniel Smith  wrote:
>>
>>
>> The problem is that most of the time, even if you're using concurrency
>> internally so multiple things *could* go wrong at once, only one thing
>> actually *does* go wrong. So it's unfortunate if some existing code is
>> prepared for a specific exception that it knows can be raised, that
>> exact exception is raised... and the existing code fails to catch it
>> because now it's wrapped in an EG.
>
> Yes, this was discussed at length on this list. Raising an exception group is 
> an API-breaking change. If a function starts raising exception groups its 
> callers need to be prepared for that. Realistically we think exception groups 
> will be raised by new APIs.  We tried and were unable to define exception 
> group semantics for except that would be reasonable and backwards compatible. 
> That's why we added except*.

Sure. This was in my list of reasons why the backwards compatibility
tradeoffs are forcing us into awkward compromises. I only elaborated
on it b/c in your last email you said you didn't understand why this
was a problem :-). And except* is definitely useful. But I think there
are options for 'except' that haven't been considered fully.

Saying that you have to make a new API every time you start using
concurrency inside a function is extremely restrictive. The whole
point of structured concurrency (and structured programming in
general) is that function callers don't need to know about the control
flow decisions inside a function. So right now, the EG proposal is
like saying that if you every have a function that doesn't contain a
'for' loop, and then you want to add a 'for' loop, then you have to
define a whole new API instead of modifying the existing one.

I absolutely get why the proposal looks like that. I'm just making the
point that we should make sure we've exhausted all our options before
settling for that as a compromise.

>> > It is easy enough to write a denormalize() function in traceback.py that 
>> > constructs this from the current EG structure, if you need it (use the 
>> > leaf_generator from the PEP). I'm not sure I see why we should trouble the 
>> > interpreter with this.
>>
>> In the current design, once an exception is wrapped in an EG, then it
>> can never be unwrapped, because its traceback information is spread
>> across the individual exception + the EG tree around it. This is
>> confusing to users ("how do I check errno?"), and makes the design
>> more complicated (the need for topology-preserving .split(), the
>> inability to define a sensible EG.__iter__, ...). The advantage of
>> making the denormalized form the native form is that now the leaf
>> exceptions would be self-contained objects like they are now, so you
>> don't need EG nesting at all, and users can write intuitive code like:
>>
>> except OSError as *excs:
>> remainder = [exc for exc in excs if exc.errno != ...]
>> if remainder:
>> raise ExceptionGroup(remainder)
>
>
> We have this precise example in the PEP:
>match, rest = excs.split(lambda e: e.errno != ...)
>
> You use split() instead of iteration for that.  split() preserves all 
> __context__, __cause__ and __traceback__ information, on all leaf and 
> non-leaf exceptions.

Well, yeah, I know, I'm the one who invented split() :-). My point was
to compare these two options: in the flat EG example, most Python
users could write and read that code without knowing anything except
"there can be multiple exceptions now". It's all old, well-known
constructs used in the obvious way.

For the .split() version, you have to write a lambda (which is allowed
to access parts of the exception object, but not all of it!), and use
this idiosyncratic method that only makes sense if you know about EG
tree structures. That's a lot more stuff that users have to understand
and hold in their head.

Or here's another example. Earlier you suggested:

> If you are using concurrency internally and don't want to raise EGs 
> externally, then surely you will catch EGs, select one of the exceptions to 
> raise and throw away all the others

But with nested EGs, this is difficult, because you *can't* just pull
out one of the exceptions to raise. The leaf exceptions aren't
standalone objects; you need some obscure traceback manipulation to do
this. I guarantee that users will get this wrong, even if we provide
the tools, because the explanation about when and why you need the
tools is complicated and people won't internalize it.

With flat EGs, this is trivial: it's just `raise
ExceptionGroup[the_selected_exception_index]`.

>> > For display purposes, it is probably nicer to look at a normalized 
>> > traceback where common parts are not repeated.
>>
>> Yeah, I agree; display code would want to re-normalize before
>> printing. But now it's only the display code that needs to care about
>> figuring out shared parts of the traceback, rathe

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Paul Bryan
As demonstrated, protocols don't get us there because duck typing isn't
a matter of having an object exhibit all of the attributes of a duck,
but rather some subset of attributes to be used by the consumer. I want
this duck to quack; someone else will want it to waddle. I don't see
how type hints could reasonably support "file like object" in the duck
type sense (unless the consumer were to specify the exact attributes of
the duck it's interested in, which I fear would become a tedious type
writing style). 

I too have sensed static typing driving the typing development agenda
in Python recently, causing other typing methods to take a back seat,
so to speak. I add my voice to those requesting Python handle other
typing methods.

Barring an innovation to allow a "subset" of a type to be declared in a
type hint, I would conclude that static typing and duck typing are
diametrically opposed. If we agree that both are valuable, developers
could build consensus on that point, and work to ensure that one does
not move forward at the expense of the other.

Paul

On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
> Thanks Mark for posting this. I know some of us are uneasy about the
> pace of the typing train 
> 
> On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith 
> wrote:
> > > If you guarded your code with `isinstance(foo, Sequence)` then I
> > could
> > > not use it with my `Foo` even if my `Foo` quacked like a
> > sequence. I was
> > > forced to use nominal typing; inheriting from Sequence, or
> > explicitly
> > > registering as a Sequence.
> > 
> > You say this like it's a bad thing, but how is this avoidable, even
> > in
> > principle? Structural typing lets you check whether Foo is duck-
> > shaped
> > -- has appropriate attribute names, etc. But quacking like a duck
> > is
> > harder: you also have to implement the Sequence behavioral
> > contract,
> > and realistically the only way to know that is if the author of Foo
> > tells you.
> > 
> 
> 
> But that's not what duck typing is (at least to me :-) ) For a given
> function, I need the passed in object to quack (and yes, I need that
> quack to sound like a duck) -- but I usually don't care whether that
> object waddles like a duck.
> 
> So yes, isinstance(obj, Sequence) is really the only way to know that
> obj is a Sequence in every important way -- but if you only need it
> to do one or two things like a Sequence, then you don't care.
> 
> And this is not uncommon -- I suspect it's very rare for a single
> function to use most of the methods of a given ABC (or protocol, or
> whatever).
> 
> And a lot of the standard library works exactly this way. Two
> examples (chosen arbitrarily, I just happen to have thought about how
> they work):
> 
> json.load() simply calls ``fp.read()``, and passes the result on down
> to json.loads(). That's it -- no checking of anything.
> 
> If fp does not have a read() method, you get an AttributeError. If fp
> has a read() method, but it returns something other than a string,
> then you get some other Exception. And if it returns a string, but
> that string isn't valid JSON, you get yet another kind of error.
> 
> In short, json.load(fp, ...) requires fp to have a read() method that
> returns a valid JSON string. But it doesn't check, nor does it need
> to, if it's getting an actual io.TextIOBase object. Is that the right
> one? I'm not totally sure, which I kind of think makes my point --
> I've been using "file-like" objects for years (decades) without
> worrying about it.
> 
> Example 2:
> 
> The str.translate method takes:
> 
> "a mapping of Unicode ordinals to Unicode ordinals, strings, or None"
> 
> Ok, then you need to pass in a Mapping, yes? Well, no you don't. The
> docs go on to say:
> 
> The table must implement lookup/indexing via __getitem__, for
> instance a
> dictionary or list.
> 
> Ah -- so we don't need a Mapping -- we need anything indexable by an
> integer that contains "ordinals, strings, or None". What the heck ABC
> could we use for that?
> 
> The ABCs do have an already complex hierarchy of containers, but
> there is no "Indexable", (quacks) and certainly no "indexable and
> returns these particular things. (quacks a certain way). (maybe
> there's something in the typing module that would work for static
> typing -- I have no idea).
> 
> I'm pretty sure this particular API was designed to accommodate the
> old py2 str.translate, which took a length-256 sequence, while also
> accommodating full Unicode, which would have required a 2^32 length
> sequence to do the same thing :-)
> 
> But again -- this is duck typing, built into the stdlib, and it works
> just fine.
> 
> Granted, until PEP 563 (kind of) , there has been nothing that
> weakens or disallows such duck typing -- those of us that want to
> write fully duck-typed code can continue to do so.
> 
> But there is the "culture" of Python -- and it has been very much
> shifting toward more typing -- A recent publication (sorry can't fi

[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread Irit Katriel via Python-Dev
On Wed, Apr 21, 2021 at 11:22 PM Nathaniel Smith  wrote:

>
>
> Saying that you have to make a new API every time you start using
> concurrency inside a function is extremely restrictive.


You don't need a new API when you start using concurrency inside a
function. You need a new API when you start raising exception groups from a
function because that changes the function's external behaviour.

-1 from me on the denormalized traceback idea. I've said what I had to say
about it in my previous email.

Cheers
Irit
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/HVPVPRSTJMI7KOFXQLJJCRUPC2R4IE42/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Jelle Zijlstra
El mié, 21 abr 2021 a las 15:30, Paul Bryan () escribió:

> As demonstrated, protocols don't get us there because duck typing isn't a
> matter of having an object exhibit all of the attributes of a duck, but
> rather some subset of attributes to be used by the consumer. I want this
> duck to quack; someone else will want it to waddle. I don't see how type
> hints could reasonably support "file like object" in the duck type sense
> (unless the consumer were to specify the exact attributes of the duck it's
> interested in, which I fear would become a tedious type writing style). '
>

This approach (a Protocol that declares exactly what you need the file-like
object to do) is in fact what we've been doing in typeshed, the repository
that provides type hints for the standard library. For those unfamiliar, it
would look something like this:

from typing import Protocol

class SupportsRead(Protocol):
def read(self) -> bytes: ...

def uses_a_file(f: SupportsRead) -> None:
 f.read()

That's somewhat tedious, to be sure, but it is working duck typing.


>
> I too have sensed static typing driving the typing development agenda in
> Python recently, causing other typing methods to take a back seat, so to
> speak. I add my voice to those requesting Python handle other typing
> methods.
>
> Barring an innovation to allow a "subset" of a type to be declared in a
> type hint, I would conclude that static typing and duck typing are
> diametrically opposed. If we agree that both are valuable, developers could
> build consensus on that point, and work to ensure that one does not move
> forward at the expense of the other.
>
What would you suggest? Should the syntax for declaring Protocols be more
concise?


>
> Paul
>
> On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
>
> Thanks Mark for posting this. I know some of us are uneasy about the pace
> of the typing train 
>
> On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith  wrote:
>
> > If you guarded your code with `isinstance(foo, Sequence)` then I could
> > not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> > forced to use nominal typing; inheriting from Sequence, or explicitly
> > registering as a Sequence.
>
> You say this like it's a bad thing, but how is this avoidable, even in
> principle? Structural typing lets you check whether Foo is duck-shaped
> -- has appropriate attribute names, etc. But quacking like a duck is
> harder: you also have to implement the Sequence behavioral contract,
> and realistically the only way to know that is if the author of Foo
> tells you.
>
>
> But that's not what duck typing is (at least to me :-) ) For a given
> function, I need the passed in object to quack (and yes, I need that quack
> to sound like a duck) -- but I usually don't care whether that object
> waddles like a duck.
>
> So yes, isinstance(obj, Sequence) is really the only way to know that obj
> is a Sequence in every important way -- but if you only need it to do one
> or two things like a Sequence, then you don't care.
>
> And this is not uncommon -- I suspect it's very rare for a single function
> to use most of the methods of a given ABC (or protocol, or whatever).
>
> And a lot of the standard library works exactly this way. Two examples
> (chosen arbitrarily, I just happen to have thought about how they work):
>
> json.load() simply calls ``fp.read()``, and passes the result on down to
> json.loads(). That's it -- no checking of anything.
>
> If fp does not have a read() method, you get an AttributeError. If fp has
> a read() method, but it returns something other than a string, then you get
> some other Exception. And if it returns a string, but that string isn't
> valid JSON, you get yet another kind of error.
>
> In short, json.load(fp, ...) requires fp to have a read() method that
> returns a valid JSON string. But it doesn't check, nor does it need to, if
> it's getting an actual io.TextIOBase object. Is that the right one? I'm not
> totally sure, which I kind of think makes my point -- I've been using
> "file-like" objects for years (decades) without worrying about it.
>
> Example 2:
>
> The str.translate method takes:
>
> "a mapping of Unicode ordinals to Unicode ordinals, strings, or None"
>
> Ok, then you need to pass in a Mapping, yes? Well, no you don't. The docs
> go on to say:
>
> The table must implement lookup/indexing via __getitem__, for instance a
> dictionary or list.
>
> Ah -- so we don't need a Mapping -- we need anything indexable by an
> integer that contains "ordinals, strings, or None". What the heck ABC could
> we use for that?
>
> The ABCs do have an already complex hierarchy of containers, but there is
> no "Indexable", (quacks) and certainly no "indexable and returns these
> particular things. (quacks a certain way). (maybe there's something in the
> typing module that would work for static typing -- I have no idea).
>
> I'm pretty sure this particular API was designed to accommodate the old
> 

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Paul Bryan
I agree, that's duck typing with a protocol, and precisely the tedious
type style I would want to avoid.

I don't know what would be a good suggestion. Something where you
reference a "fully equipped" type and cherry pick the attributes you
want? Something like `Protocol[Duck, ("quack", "waddle")]`?

Paul
 

On Wed, 2021-04-21 at 16:13 -0700, Jelle Zijlstra wrote:
> 
> 
> El mié, 21 abr 2021 a las 15:30, Paul Bryan ()
> escribió:
> > As demonstrated, protocols don't get us there because duck typing
> > isn't a matter of having an object exhibit all of the attributes of
> > a duck, but rather some subset of attributes to be used by the
> > consumer. I want this duck to quack; someone else will want it to
> > waddle. I don't see how type hints could reasonably support "file
> > like object" in the duck type sense (unless the consumer were to
> > specify the exact attributes of the duck it's interested in, which
> > I fear would become a tedious type writing style). '
> > 
> 
> 
> This approach (a Protocol that declares exactly what you need the
> file-like object to do) is in fact what we've been doing in typeshed,
> the repository that provides type hints for the standard library. For
> those unfamiliar, it would look something like this:
> 
> from typing import Protocol
> 
> class SupportsRead(Protocol):
>     def read(self) -> bytes: ...
> 
> def uses_a_file(f: SupportsRead) -> None:
>      f.read()
> 
> That's somewhat tedious, to be sure, but it is working duck typing.
>  
> > 
> > I too have sensed static typing driving the typing development
> > agenda in Python recently, causing other typing methods to take a
> > back seat, so to speak. I add my voice to those requesting Python
> > handle other typing methods.
> > 
> > Barring an innovation to allow a "subset" of a type to be declared
> > in a type hint, I would conclude that static typing and duck typing
> > are diametrically opposed. If we agree that both are valuable,
> > developers could build consensus on that point, and work to ensure
> > that one does not move forward at the expense of the other.
> > 
> 
> What would you suggest? Should the syntax for declaring Protocols be
> more concise?
>  
> > 
> > Paul
> > 
> > On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
> > > Thanks Mark for posting this. I know some of us are uneasy about
> > > the pace of the typing train 
> > > 
> > > On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith 
> > > wrote:
> > > > > If you guarded your code with `isinstance(foo, Sequence)`
> > > > then I could
> > > > > not use it with my `Foo` even if my `Foo` quacked like a
> > > > sequence. I was
> > > > > forced to use nominal typing; inheriting from Sequence, or
> > > > explicitly
> > > > > registering as a Sequence.
> > > > 
> > > > You say this like it's a bad thing, but how is this avoidable,
> > > > even in
> > > > principle? Structural typing lets you check whether Foo is
> > > > duck-shaped
> > > > -- has appropriate attribute names, etc. But quacking like a
> > > > duck is
> > > > harder: you also have to implement the Sequence behavioral
> > > > contract,
> > > > and realistically the only way to know that is if the author of
> > > > Foo
> > > > tells you.
> > > > 
> > > 
> > > 
> > > But that's not what duck typing is (at least to me :-) ) For a
> > > given function, I need the passed in object to quack (and yes, I
> > > need that quack to sound like a duck) -- but I usually don't care
> > > whether that object waddles like a duck.
> > > 
> > > So yes, isinstance(obj, Sequence) is really the only way to know
> > > that obj is a Sequence in every important way -- but if you only
> > > need it to do one or two things like a Sequence, then you don't
> > > care.
> > > 
> > > And this is not uncommon -- I suspect it's very rare for a single
> > > function to use most of the methods of a given ABC (or protocol,
> > > or whatever).
> > > 
> > > And a lot of the standard library works exactly this way. Two
> > > examples (chosen arbitrarily, I just happen to have thought about
> > > how they work):
> > > 
> > > json.load() simply calls ``fp.read()``, and passes the result on
> > > down to json.loads(). That's it -- no checking of anything.
> > > 
> > > If fp does not have a read() method, you get an AttributeError.
> > > If fp has a read() method, but it returns something other than a
> > > string, then you get some other Exception. And if it returns a
> > > string, but that string isn't valid JSON, you get yet another
> > > kind of error.
> > > 
> > > In short, json.load(fp, ...) requires fp to have a read() method
> > > that returns a valid JSON string. But it doesn't check, nor does
> > > it need to, if it's getting an actual io.TextIOBase object. Is
> > > that the right one? I'm not totally sure, which I kind of think
> > > makes my point -- I've been using "file-like" objects for years
> > > (decades) without worrying about it.
> > > 
> > > Example 2:
> > > 
> > > The str.translate method takes:

[Python-Dev] Re: PEP 654: Exception Groups and except* [REPOST]

2021-04-21 Thread Guido van Rossum
On Wed, Apr 21, 2021 at 3:26 PM Nathaniel Smith  wrote:

> On Tue, Apr 20, 2021 at 3:15 AM Irit Katriel 
> wrote:
> > On Tue, Apr 20, 2021 at 2:48 AM Nathaniel Smith  wrote:
> >>
> >>
> >> The problem is that most of the time, even if you're using concurrency
> >> internally so multiple things *could* go wrong at once, only one thing
> >> actually *does* go wrong. So it's unfortunate if some existing code is
> >> prepared for a specific exception that it knows can be raised, that
> >> exact exception is raised... and the existing code fails to catch it
> >> because now it's wrapped in an EG.
> >
> > Yes, this was discussed at length on this list. Raising an exception
> group is an API-breaking change. If a function starts raising exception
> groups its callers need to be prepared for that. Realistically we think
> exception groups will be raised by new APIs.  We tried and were unable to
> define exception group semantics for except that would be reasonable and
> backwards compatible. That's why we added except*.
>
> Sure. This was in my list of reasons why the backwards compatibility
> tradeoffs are forcing us into awkward compromises. I only elaborated
> on it b/c in your last email you said you didn't understand why this
> was a problem :-). And except* is definitely useful. But I think there
> are options for 'except' that haven't been considered fully.
>

Do you have any suggestions, or are you just telling us to think harder?
Because we've already thought as hard as we could and within all the
constraints (backwards compatibility and otherwise) we just couldn't think
of a better one.


> Saying that you have to make a new API every time you start using
> concurrency inside a function is extremely restrictive. The whole
> point of structured concurrency (and structured programming in
> general) is that function callers don't need to know about the control
> flow decisions inside a function. So right now, the EG proposal is
> like saying that if you every have a function that doesn't contain a
> 'for' loop, and then you want to add a 'for' loop, then you have to
> define a whole new API instead of modifying the existing one.
>

That analogy doesn't fly. If "what exceptions can this raise" is not part
of the function spec (so users who catch exceptions are already flying
blind or guessing based on what they've seen happen in the past), then you
can certainly switch to using EGs, and this *is* like adding a for-loop.
But if the exceptions that a function raises *are* part of its spec, and
users are catching them, then switching to concurrency (without catching
and converting EGs in the function) *is* an API change, akin to taking a
function that returns an int and changing it to (sometimes?) returning a
list of ints.


> I absolutely get why the proposal looks like that. I'm just making the
> point that we should make sure we've exhausted all our options before
> settling for that as a compromise.
>

But if you're not able to make constructive proposals I have to conclude
that we *have* exhausted our options, and we should move on.


> >> > It is easy enough to write a denormalize() function in traceback.py
> that constructs this from the current EG structure, if you need it (use the
> leaf_generator from the PEP). I'm not sure I see why we should trouble the
> interpreter with this.
> >>
> >> In the current design, once an exception is wrapped in an EG, then it
> >> can never be unwrapped, because its traceback information is spread
> >> across the individual exception + the EG tree around it. This is
> >> confusing to users ("how do I check errno?"), and makes the design
> >> more complicated (the need for topology-preserving .split(), the
> >> inability to define a sensible EG.__iter__, ...). The advantage of
> >> making the denormalized form the native form is that now the leaf
> >> exceptions would be self-contained objects like they are now, so you
> >> don't need EG nesting at all, and users can write intuitive code like:
> >>
> >> except OSError as *excs:
> >> remainder = [exc for exc in excs if exc.errno != ...]
> >> if remainder:
> >> raise ExceptionGroup(remainder)
> >
> >
> > We have this precise example in the PEP:
> >match, rest = excs.split(lambda e: e.errno != ...)
> >
> > You use split() instead of iteration for that.  split() preserves all
> __context__, __cause__ and __traceback__ information, on all leaf and
> non-leaf exceptions.
>
> Well, yeah, I know, I'm the one who invented split() :-). My point was
> to compare these two options: in the flat EG example, most Python
> users could write and read that code without knowing anything except
> "there can be multiple exceptions now". It's all old, well-known
> constructs used in the obvious way.
>
> For the .split() version, you have to write a lambda (which is allowed
> to access parts of the exception object, but not all of it!), and use
> this idiosyncratic method that only makes sense if you know about EG
> tree s

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Caleb Donovick
My personal motivating example for PEP 637 was shorthand for protocols.
`x: Protocol[foo=int, bar=Callable[str, int]]` could say x has attribute
foo which is an int and method bar from str to int.



On Wed, Apr 21, 2021 at 4:23 PM Paul Bryan  wrote:

> I agree, that's duck typing with a protocol, and precisely the tedious
> type style I would want to avoid.
>
> I don't know what would be a good suggestion. Something where you
> reference a "fully equipped" type and cherry pick the attributes you want?
> Something like `Protocol[Duck, ("quack", "waddle")]`?
>
> Paul
>
>
> On Wed, 2021-04-21 at 16:13 -0700, Jelle Zijlstra wrote:
>
>
>
> El mié, 21 abr 2021 a las 15:30, Paul Bryan () escribió:
>
> As demonstrated, protocols don't get us there because duck typing isn't a
> matter of having an object exhibit all of the attributes of a duck, but
> rather some subset of attributes to be used by the consumer. I want this
> duck to quack; someone else will want it to waddle. I don't see how type
> hints could reasonably support "file like object" in the duck type sense
> (unless the consumer were to specify the exact attributes of the duck it's
> interested in, which I fear would become a tedious type writing style). '
>
>
> This approach (a Protocol that declares exactly what you need the
> file-like object to do) is in fact what we've been doing in typeshed, the
> repository that provides type hints for the standard library. For those
> unfamiliar, it would look something like this:
>
> from typing import Protocol
>
> class SupportsRead(Protocol):
> def read(self) -> bytes: ...
>
> def uses_a_file(f: SupportsRead) -> None:
>  f.read()
>
> That's somewhat tedious, to be sure, but it is working duck typing.
>
>
>
> I too have sensed static typing driving the typing development agenda in
> Python recently, causing other typing methods to take a back seat, so to
> speak. I add my voice to those requesting Python handle other typing
> methods.
>
> Barring an innovation to allow a "subset" of a type to be declared in a
> type hint, I would conclude that static typing and duck typing are
> diametrically opposed. If we agree that both are valuable, developers could
> build consensus on that point, and work to ensure that one does not move
> forward at the expense of the other.
>
> What would you suggest? Should the syntax for declaring Protocols be more
> concise?
>
>
>
> Paul
>
> On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
>
> Thanks Mark for posting this. I know some of us are uneasy about the pace
> of the typing train 
>
> On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith  wrote:
>
> > If you guarded your code with `isinstance(foo, Sequence)` then I could
> > not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> > forced to use nominal typing; inheriting from Sequence, or explicitly
> > registering as a Sequence.
>
> You say this like it's a bad thing, but how is this avoidable, even in
> principle? Structural typing lets you check whether Foo is duck-shaped
> -- has appropriate attribute names, etc. But quacking like a duck is
> harder: you also have to implement the Sequence behavioral contract,
> and realistically the only way to know that is if the author of Foo
> tells you.
>
>
> But that's not what duck typing is (at least to me :-) ) For a given
> function, I need the passed in object to quack (and yes, I need that quack
> to sound like a duck) -- but I usually don't care whether that object
> waddles like a duck.
>
> So yes, isinstance(obj, Sequence) is really the only way to know that obj
> is a Sequence in every important way -- but if you only need it to do one
> or two things like a Sequence, then you don't care.
>
> And this is not uncommon -- I suspect it's very rare for a single function
> to use most of the methods of a given ABC (or protocol, or whatever).
>
> And a lot of the standard library works exactly this way. Two examples
> (chosen arbitrarily, I just happen to have thought about how they work):
>
> json.load() simply calls ``fp.read()``, and passes the result on down to
> json.loads(). That's it -- no checking of anything.
>
> If fp does not have a read() method, you get an AttributeError. If fp has
> a read() method, but it returns something other than a string, then you get
> some other Exception. And if it returns a string, but that string isn't
> valid JSON, you get yet another kind of error.
>
> In short, json.load(fp, ...) requires fp to have a read() method that
> returns a valid JSON string. But it doesn't check, nor does it need to, if
> it's getting an actual io.TextIOBase object. Is that the right one? I'm not
> totally sure, which I kind of think makes my point -- I've been using
> "file-like" objects for years (decades) without worrying about it.
>
> Example 2:
>
> The str.translate method takes:
>
> "a mapping of Unicode ordinals to Unicode ordinals, strings, or None"
>
> Ok, then you need to pass in a Mapping, yes? Well, no you

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Carol Willing
Luciano,

Thank you for such a thoughtful and eloquent response. Your wisdom is
definitely appreciated, and I agree this is an opportunity to go forward
with more clarity. I'm so proud of the Python dev community for their
thoughtful and respectful conversation.

All, Without the efforts of Larry, Guido, Mark, Lukasz, Luciano,
the pydantic/FastAPI folks, the Steering Council and their willingness
listen and problem solve, the outcome would have been far less appealing
and useful.

Thank you!

Carol

On Wed, Apr 21, 2021 at 4:26 PM Paul Bryan  wrote:

> I agree, that's duck typing with a protocol, and precisely the tedious
> type style I would want to avoid.
>
> I don't know what would be a good suggestion. Something where you
> reference a "fully equipped" type and cherry pick the attributes you want?
> Something like `Protocol[Duck, ("quack", "waddle")]`?
>
> Paul
>
>
> On Wed, 2021-04-21 at 16:13 -0700, Jelle Zijlstra wrote:
>
>
>
> El mié, 21 abr 2021 a las 15:30, Paul Bryan () escribió:
>
> As demonstrated, protocols don't get us there because duck typing isn't a
> matter of having an object exhibit all of the attributes of a duck, but
> rather some subset of attributes to be used by the consumer. I want this
> duck to quack; someone else will want it to waddle. I don't see how type
> hints could reasonably support "file like object" in the duck type sense
> (unless the consumer were to specify the exact attributes of the duck it's
> interested in, which I fear would become a tedious type writing style). '
>
>
> This approach (a Protocol that declares exactly what you need the
> file-like object to do) is in fact what we've been doing in typeshed, the
> repository that provides type hints for the standard library. For those
> unfamiliar, it would look something like this:
>
> from typing import Protocol
>
> class SupportsRead(Protocol):
> def read(self) -> bytes: ...
>
> def uses_a_file(f: SupportsRead) -> None:
>  f.read()
>
> That's somewhat tedious, to be sure, but it is working duck typing.
>
>
>
> I too have sensed static typing driving the typing development agenda in
> Python recently, causing other typing methods to take a back seat, so to
> speak. I add my voice to those requesting Python handle other typing
> methods.
>
> Barring an innovation to allow a "subset" of a type to be declared in a
> type hint, I would conclude that static typing and duck typing are
> diametrically opposed. If we agree that both are valuable, developers could
> build consensus on that point, and work to ensure that one does not move
> forward at the expense of the other.
>
> What would you suggest? Should the syntax for declaring Protocols be more
> concise?
>
>
>
> Paul
>
> On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
>
> Thanks Mark for posting this. I know some of us are uneasy about the pace
> of the typing train 
>
> On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith  wrote:
>
> > If you guarded your code with `isinstance(foo, Sequence)` then I could
> > not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> > forced to use nominal typing; inheriting from Sequence, or explicitly
> > registering as a Sequence.
>
> You say this like it's a bad thing, but how is this avoidable, even in
> principle? Structural typing lets you check whether Foo is duck-shaped
> -- has appropriate attribute names, etc. But quacking like a duck is
> harder: you also have to implement the Sequence behavioral contract,
> and realistically the only way to know that is if the author of Foo
> tells you.
>
>
> But that's not what duck typing is (at least to me :-) ) For a given
> function, I need the passed in object to quack (and yes, I need that quack
> to sound like a duck) -- but I usually don't care whether that object
> waddles like a duck.
>
> So yes, isinstance(obj, Sequence) is really the only way to know that obj
> is a Sequence in every important way -- but if you only need it to do one
> or two things like a Sequence, then you don't care.
>
> And this is not uncommon -- I suspect it's very rare for a single function
> to use most of the methods of a given ABC (or protocol, or whatever).
>
> And a lot of the standard library works exactly this way. Two examples
> (chosen arbitrarily, I just happen to have thought about how they work):
>
> json.load() simply calls ``fp.read()``, and passes the result on down to
> json.loads(). That's it -- no checking of anything.
>
> If fp does not have a read() method, you get an AttributeError. If fp has
> a read() method, but it returns something other than a string, then you get
> some other Exception. And if it returns a string, but that string isn't
> valid JSON, you get yet another kind of error.
>
> In short, json.load(fp, ...) requires fp to have a read() method that
> returns a valid JSON string. But it doesn't check, nor does it need to, if
> it's getting an actual io.TextIOBase object. Is that the right one? I'm not
> totally sure, which