[Python-Dev] Re: PEP 558: Defined semantics for locals()

2021-07-20 Thread Nick Coghlan
On Mon, 19 Jul 2021 at 22:08, Nick Coghlan  wrote:
> On Mon, 19 Jul 2021, 9:32 pm Petr Viktorin,  wrote:
>> The proposal assumes that in the future, ``PyLocals_Get``, and thus
>> ``locals()``, will never gain another kind of return value, however
>> unlikely that is.
>> AFAICS, code that uses this will usually check for a single special case
>> and fall back (or error) for the other(s), so I think it'd be reasonable
>> to make this an "enum" with two values. e.g.:
>>
>> int PyLocals_GetReturnBehavior();  # better name?
>
>
> We've used "Kind" for similar APIs elsewhere, so calling this API 
> "PyLocals_Kind()" would make sense to me.
>
> However, there's a potential point of confusion here, as there's already an 
> implementation level "locals kind" that the runtime uses. This public kind is 
> related to that internal kind, but they're not the same.

Now that I'm on my actual computer rather than my phone, some further
details on the new-in-Python-3.11 internal-only API that already
refers to "locals kind":

Typedef name: _PyLocals_Kind
Value flags: CO_FAST_LOCAL, CO_FAST_CELL, CO_FAST_FREE (with more
expected to be defined in the future)
Frame local variable lookup API: _PyLocals_GetKind, _PyLocals_SetKind

Rather than relating to the frame as a whole, these flags relate to
individual variables on the frame. CO_FAST_FREE can even be used on
non-optimised frames, since classes defined inside functions have
access to variables defined in the function scope.

Due to this, I'd definitely want to hear Mark Shannon's opinion before
we went down the path of using "PyLocals_Kind" (or variations on that
theme) as a public API, since we'd need to rename the internal APIs to
avoid confusion if we did that.

I don't think a rename would be too bad though - since the existing
flags relate to individual local variables, my suggestion would be to
use `LocalVar` instead of `Locals`, giving the revised enum name
_PyLocalVar_Kind, and _PyLocalVar_GetKind and _PyLocalVar_SetKind as
the access and update methods. (There are only 27 hits on the
_PyLocals prefix across the current 3.11 code base, all relating to
this internal API)

Cheers,
Nick.

-- 
Nick Coghlan   |   [email protected]   |   Brisbane, Australia
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/4KYGTJKJ7USCKJ7IDHXGTQPSFWV46IPA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 558: Defined semantics for locals()

2021-07-20 Thread Guido van Rossum
On Tue, Jul 20, 2021 at 4:52 AM Nick Coghlan  wrote:
[Petr]

> >> int PyLocals_GetReturnBehavior();  # better name?
>
[Nick]

> > We've used "Kind" for similar APIs elsewhere, so calling this API
> "PyLocals_Kind()" would make sense to me.
> >
> > However, there's a potential point of confusion here, as there's already
> an implementation level "locals kind" that the runtime uses. This public
> kind is related to that internal kind, but they're not the same.
>
> [Nick, responding to himself]

> Now that I'm on my actual computer rather than my phone, some further
> details on the new-in-Python-3.11 internal-only API that already
> refers to "locals kind":
>
> Typedef name: _PyLocals_Kind
> Value flags: CO_FAST_LOCAL, CO_FAST_CELL, CO_FAST_FREE (with more
> expected to be defined in the future)
> Frame local variable lookup API: _PyLocals_GetKind, _PyLocals_SetKind
>
> Rather than relating to the frame as a whole, these flags relate to
> individual variables on the frame. CO_FAST_FREE can even be used on
> non-optimised frames, since classes defined inside functions have
> access to variables defined in the function scope.
>
> Due to this, I'd definitely want to hear Mark Shannon's opinion before
> we went down the path of using "PyLocals_Kind" (or variations on that
> theme) as a public API, since we'd need to rename the internal APIs to
> avoid confusion if we did that.
>
> I don't think a rename would be too bad though - since the existing
> flags relate to individual local variables, my suggestion would be to
> use `LocalVar` instead of `Locals`, giving the revised enum name
> _PyLocalVar_Kind, and _PyLocalVar_GetKind and _PyLocalVar_SetKind as
> the access and update methods. (There are only 27 hits on the
> _PyLocals prefix across the current 3.11 code base, all relating to
> this internal API)
>

My name isn't Mark Shannon, but I was involved in picking this name. I
think it's fine to rename this concept to "local variable kind" and spell
the typedef as you propose, though I think I'd like it slightly better to
switch from "Locals" to "Local", and to put the underscore after that:
`_PyLocal_VarKind`, `_PyLocal_GetVarKind()`, `_PyLocal_SetVarKind()`. (The
API for this is very much in flux -- we'll settle by 3.11 beta 1 though. I
expect we'll also have some Python-level public (but unstable) API to
access these flags, so people can play around with this stuff.)

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

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


[Python-Dev] RFC for PEP 663: Improving and Standardizing Enum str(), repr(), and format() behaviors

2021-07-20 Thread Ethan Furman

PEP: 663
Title: Improving and Standardizing Enum str(), repr(), and format() behaviors
Version: $Revision$
Last-Modified: $Date$
Author: Ethan Furman 
Discussions-To: [email protected]
Status: Draft
Type: Informational
Content-Type: text/x-rst
Created: 23-Feb-2013
Python-Version: 3.11
Post-History: 20-Jul-2021
Resolution:


Abstract


Now that we have a few years experience with Enum usage it is time to update
the ``repr()``, ``str()``, and ``format()`` of the various enumerations by their
intended purpose.


Motivation
==

The addition of ``StrEnum`` with its requirement to have its ``str()`` be its
``value`` is inconsistent with other provided Enum's ``str``.

Having the ``str()`` of ``IntEnum`` and ``IntFlag`` not be the value causes
bugs and extra work when replacing existing constants.

Having the ``str()`` and ``format()`` of an enum member be different can be
confusing.

The iteration of ``Flag`` members, which directly affects their ``repr()``, is
inelegant at best, and buggy at worst.


Rationale
=

Enums are becoming more common in the standard library; being able to recognize
enum members by their ``repr()``, and having that ``repr()`` be easy to parse, 
is
useful and can save time and effort in understanding and debugging code.

However, the enums with mixed-in data types (``IntEnum``, ``IntFlag``, and the 
new
``StrEnum``) need to be more backwards compatible with the constants they are
replacing -- specifically, ``str(replacement_enum_member) == 
str(original_constant)``
should be true (and the same for ``format()``).

IntEnum, IntFlag, and StrEnum should be as close to a drop-in replacement of
existing integer and string constants as is possible.  Towards that goal, the
str() output of each should be its inherent value; i.e.::

>>> Color.RED

>>> str(Color.RED)
1
>>> format(Color.RED)
'1'

Note that format() already produces the correct output, only str() needs
updating.

As much as possible, the ``str()`, ``repr()``, and ``format()`` of enum members
should be standardized across the stardard library.

The repr() of Flag currently includes aliases, which it should not; fixing that
will, of course, already change its ``repr()`` in certain cases.


Specification
=

There a three broad categories of enum usage:

- standard: Enum or Flag
  a new enum class is created, and the members are used as ``class.member_name``

- drop-in replacement: IntEnum, IntFlag, StrEnum
  a new enum class is created which also subclasses ``int`` or ``str`` and uses
  ``int.__str__`` or ``str.__str__``; the ``repr`` can be changed by using the
  ``global_enum`` decorator

- user-mixed enums and flags
  the user creates their own integer-, float-, str-, whatever-enums instead of
  using enum.IntEnum, etc.

Some sample enums::

# module: tools.py

class Hue(Enum):  # or IntEnum
LIGHT = -1
NORMAL = 0
DARK = +1

class Color(Flag):  # or IntFlag
RED = 1
GREEN = 2
BLUE = 4

class Grey(int, Enum):  # or (int, Flag)
   BLACK = 0
   WHITE = 1

Using the above enumerations, the following table shows the old and new
behavior, while the last shows the final result:


+-+--+-++---+---++---+
| type   | enum repr() | enum str() | enum format() | flag repr()   | flag str() 
| flag format() |

+-+--+-++---+---++---+
| standard| 3.9  | ||   |   | 
Color.RED|GREEN| Color.RED|GREEN   |
| 
+--+-++---+---++---+
| | new  | ||   |  | 
Color.RED|Color.GREEN  | Color.RED|Color.GREEN |

+-+--+-++---+---++---+
+-+--+-++---+---++---+
| user mixed  | 3.9  | || 1 || 
| 1 |
| 
+--+-++---+---++---+
| | new  | || Grey.WHITE|   | 
| Grey.WHITE|

+-+--+-++---+---++---+
+-+--