On Sat, Apr 23, 2022 at 2:39 PM Rob Cliffe via Python-Dev <
python-dev@python.org> wrote:

> UGH!
>

I understand you don't like the proposal, but do please try to keep it
civil. It's totally okay to say you don't like something, but I don't think
anyone would take kindly to someone coming up to them in person and going,
"UGH!" in their face about an idea they had.

-Brett


>
> I thought there was a general understanding that when typing was added
> to Python, there would be no impact, or at least minimal impact, on
> people who didn't use it.  (Raises hand.)
> Now we see an(other) instance of intention creep.
> Rob Cliffe
>
> On 23/04/2022 02:13, Larry Hastings wrote:
> >
> >
> > This document is a loose proto-PEP for a new "forward class" /
> > "continue class" syntax.  Keep in mind, the formatting is a mess. If I
> > wind up submitting it as a real PEP I'll be sure to clean it up first.
> >
> >
> > /arry
> >
> > --------------------------------------
> >
> >
> > PEP XXXX: Forward declaration of classes
> >
> > Overview
> > --------
> >
> > Python currently has one statement to define a class, the `class`
> > statement:
> >
> > ```Python
> >     class X():
> >         # class body goes here
> >         def __init__(self, key):
> >             self.key = key
> > ```
> >
> > This single statement declares the class, including its bases and
> > metaclass,
> > and also defines the contents of the class in the "class body".
> >
> > This PEP proposes an additional syntax for declaring a class which splits
> > this work across two statements:
> > * The first statement is `forward class`, which declares the class and
> > binds
> >   the class object.
> > * The second statement is `continue class`, which defines the contents
> >   of the class in the "class body".
> >
> > To be clear: `forward class` creates the official, actual class object.
> > Code that wants to take a reference to the class object may take
> > references
> > to the `forward class` declared class, and interact with it as normal.
> > However, a class created by `forward class` can't be *instantiated*
> > until after the matching `continue class` statement finishes.
> >
> > Defining class `X` from the previous example using this new syntax
> > would read
> > as follows:
> >
> > ```
> >     forward class X()
> >
> >     continue class X:
> >         # class body goes here
> >         def __init__(self, key):
> >             self.key = key
> > ```
> >
> > This PEP does not propose altering or removing the traditional `class`
> > statement;
> > it would continue to work as before.
> >
> >
> > Rationale
> > ---------
> >
> > Python programmers have had a minor problem with classes for years:
> > there's
> > no way to have early-bound circular dependencies between objects. If A
> > depends on B, and B depends on A, there's no linear order that allows
> > you to cleanly declare both.
> >
> > Most of the time, the dependencies were in late-binding code, e.g. A
> > refers
> > to B inside a method.  So this was rarely an actual problem at
> > runtime.  When
> > this problem did arise, in code run at definition-time, it was usually
> > only
> > a minor headache and could be easily worked around.
> >
> > But the explosion of static type analysis in Python, particularly with
> > the `typing` module and the `mypy` tool, has made circular
> > definition-time
> > dependencies between classes commonplace--and much harder to solve.
> > Here's
> > one simple example:
> >
> > ```Python
> >     class A:
> >         value: B
> >
> >     class B:
> >         value: A
> > ```
> >
> > An attribute of `B` is defined using a type annotation of `A`, and an
> > attribute of `A` is defined using a type annotation of `B`. There's
> > no order to these two definitions that works; either `A` isn't defined
> > yet, or `B` isn't defined yet.
> >
> > Various workarounds and solutions have been proposed to solve this
> > problem,
> > including two PEPs: PEP 563 (automatic stringized annotations) and PEP
> > 649
> > (delayed evaluation of annotations using functions).
> > But nothing so far has been both satisfying and complete; either it
> > is wordy and clumsy to use (manually stringizing annotations), or it
> > added restrictions and caused massive code breakage for runtime use of
> > annotations (PEP 563), or simply didn't solve every problem (PEP 649).
> > This proposed  `forward class` / `continue class` syntax should permit
> > solving *every* forward-reference and circular-reference problem faced
> > in Python, using an elegant and Pythonic new syntax.
> >
> > As a side benefit, `forward class` and `continue class` syntax enables
> > rudimentary separation of "interface" from "implementation", at least for
> > classes.  A user seeking to "hide" the implementation details of their
> > code could put their class definitions in one module, and the
> > implementations of those classes in a different module.
> >
> > This new syntax is not intended to replace the traditional `class`
> > declaration syntax in Python.  If this PEP were accepted, the `class`
> > statement would still be the preferred mechanism for creating classes
> > in Python; `forward class` should only be used when it confers some
> > specific benefit.
> >
> >
> > Syntax
> > ------
> >
> > The `forward class` statement is the same as the `class` statement,
> > except it doesn't end with a colon and is not followed by an indented
> > block.
> > Without any base classes or metaclass, the `forward class` statement is
> > as follows:
> >
> > ```
> >     forward class X
> > ```
> >
> > This would declare class `X`.
> >
> > If `X` needs base classes or metaclass, the corresponding `forward
> > class` statement
> > would be as follows, rendered in a sort of "function prototype" manner:
> >
> > ```
> >     forward class X(*bases, metaclass=object, **kwargs)
> > ```
> >
> > The `continue class` statement is similar to a `class` statement
> > without any bases or metaclass.  It ends with a colon,
> > and is followed by the "class body":
> >
> >     continue class X:
> >         # class body goes here
> >         pass
> >
> > One important difference: the `X` in `continue class X:` is not a *name*,
> > it's an *expression*.  This code is valid:
> >
> > ```
> >     forward class X()
> >     snodgrass = X
> >
> >     continue class snodgrass:
> >         # class body goes here
> >         pass
> > ```
> >
> > as well as this:
> >
> > ```
> >     import my_module
> >
> >     continue class my_module.X:
> >         # class body goes here
> >         pass
> > ```
> >
> > Using this new syntax, the forward-reference problem illustrated
> > in the *Rationale* section above is now easy to solve:
> >
> > ```Python
> >     forward class B
> >
> >     class A:
> >         value: B = None
> >
> >     continue class B:
> >         value: A = None
> > ```
> >
> > One final note.  Why must the base and metaclass be declared
> > with the `forward class` statement?  The point of this new
> > syntax is to allow creating the real class object, permitting
> > users of the class to take references to it early, before it's
> > fully defined.  And the class could be declared with a
> > metaclass, and the metaclass could have a `__new__`, which
> > means it's responsible for creating the class object, and
> > this syntax would have to preserve that behavior.
> >
> > (This small detail is about to complicate this proposal a great
> > deal!)
> >
> >
> > #### Semantics of forward-declared class objects
> >
> > `forward class X` declares a class, but the class is explicitly
> > not yet fully defined.  It won't be fully defined and ready to
> > be instantiated until after the corresponding `continue class`
> > statement.  We'll refer to a class object in this state as
> > a "forward-declared class object".  How does this object behave?
> >
> > As per the "consenting adults" rule, the forward-declared class
> > object must permit most operations.  You should be able to examine
> > the object, compare it to other objects, inspect some attributes
> > (`__name__`, `__mro__`, `__class__`), and even set attributes.
> >
> > However, the user isn't permitted to instantiate a forward-declared
> > class object until after the corresponding `continue class X`.
> > We ensure this with a new dunder attribute, `__forward__`,
> > which if present tells the Python runtime that this is a
> > forward-declared class object.  The `continue class` statement
> > would delete this attribute from the object, after which it
> > could be instantiated.
> >
> > (Users could work around this constraint, or even delete `__forward__`
> > if they so chose--again, the "consenting adults" rule applies.)
> >
> > It's explicitly permissible to create a forward-declared class
> > object that never gets finished with a `continue class` statement.
> > If all you need is an object that represents the class--say,
> > to satisfy static type annotation use cases--a forward-declared
> > class object works fine.
> >
> > A subsequent section will address the complexities of
> > how `forward class` and `continue class` interact with metaclasses.
> > For now, a note about forward-declared class objects declared with
> > a metaclass implementing `__prepare__`.  The forward-declared class
> > object *dict* will be the "dict-like object" returned by the
> > `metaclass.__prepare__()` method.  This "dict-like object" won't
> > be processed and discarded until after `continue class` processes
> > the class body and calls the appropriate methods in the metaclass.
> >
> >
> > #### Semantics of `continue class`
> >
> > `continue class` may only be run on a class once.
> > (As Eric V. Smith pointed out in response to an early version of
> > this proposal, allowing multiple "continue" declarations on the
> > same class would lead directly to language-condoned monkey-patching.)
> >
> >
> > #### Decorators
> >
> > Both the `forward class` and `continue class` statements
> > support decorators, and the user may use decorators with either
> > or both statements for the same class.  But now that we've
> > split the responsibilities of the `class` statement between
> > these two new statements, which decorator goes with which
> > statement becomes a novel concern.  In general, decorators
> > that don't examine the contents of the class, but simply
> > want to register the class object and its name, can decorate
> > the `forward class` statement.  Also, class decorators that
> > want to return a different object for the class should decorate
> > `forward class`.  But all decorators that meaningfully examine
> > the contents of the class should decorate the `continue class`
> > statement.
> >
> > Unfortunately, there are some decorators that can't work properly
> > with either `forward class` *or* `continue class`: a decorator
> > that meaningfully examine the declared contents of that class, but
> > also return an object other than the original class passed in.
> > In that case, the user cannot declare this class with
> > `forward class`; they must declare it with the conventional `class`
> > statement.
> >
> > #### __slots__
> >
> > This leads us to an example of a decorator that, as of 3.10,
> > wouldn't be usable with classes declared by `forward class`.
> > It's the new 3.10 feature `@dataclass(slots=True)`.  When called
> > in this way, dataclass examines the attributes of the class it
> > has decorated, dynamically constructs a new class using `__slots__`,
> > and returns this new class.
> >
> > Since this decorator meaningfully examines the class, it must
> > be used with `continue class`.  But, this decorator also returns
> > an object other the original class, which means it's inapproriate
> > for `continue class` and should be called with `forward class`.
> > What to do?
> >
> > We have a separate idea to ameliorate this specific situation.
> > Right now, a class that uses `__slots__` *must* define them in
> > the class body, as that member is read before the class name is
> > bound (or before any descriptors are run).  But we can simply
> > relax that, and make processing `__slots__` lazy, so that it
> > isn't examined until the first time the class is *instantiated.*
> > This would mean `@dataclass(slots=True)` could simply return the
> > original class, and thus would work fine when decorating a
> > `continue class` statement.
> >
> >
> > #### Metaclasses
> >
> > The existing semantics of metaclasses present a thorny problem
> > for `forward class` and `continue class`.  First, a review of
> > how class definition works.
> >
> > Most of the mechanisms involved with defining a class happen
> > internally to the interpreter.  However, there are a number
> > of special methods (aka "dunder methods") called during class
> > construction that are overridable by user code.  Empirical testing
> > with the current version of Python (as of this writing, 3.10.4)
> > reveals the order in which all this work is done.
> >
> > When Python executes the definition of this class:
> >
> > ```Python
> >     class Foo(BaseClass, metaclass=MetaClass):
> >         # class body is here
> >         pass
> > ```
> >
> > these events are visible in this order:
> >
> > 1. Python calls `MetaClass.__prepare__`.
> > 2. Python executes the "class body" for class Foo.
> > 3. Python calls `MetaClass.__new__`.
> > 4. Python calls `BaseClass.__init_subclass__`.
> >    (If multiple base classes define `__init_subclass__`,
> >    they're called in MRO order.)
> > 5. Python calls `MetaClass.__init__`.
> > 6. The `class` statement binds the class object to the name `Foo`.
> >
> > The big problem this presents for `forward class`: the
> > "class body" is executed before the `MetaClass.__new__`.
> > This is necessary because one of the parameters to `MetaClass.__new__`
> > is `namespace`, the "dict-like object" returned by
> > `MetaClass.__prepare__`
> > and initialized by executing the class body using that object
> > as a sort of locals dictionary.
> >
> > This creates a chicken-and-egg problem: `forward class` needs
> > to define the class object, but the class object is defined
> > by `MetaClass.__new__`, and `MetaClass.__new__` can't run until
> > after the class body, which we don't run until the `continue class`
> > statement, which must be after `forward class`.
> >
> > The unfortunate but necessary solution: split `__new__` into
> > two new special methods on metaclasses, `__new_forward__`
> > and `__new_continue__`.  As a reminder, here's the prototype
> > for `__new__` on a metaclass:
> >
> > ```Python
> >     def __new__(metaclass, name, bases, namespace, **kwargs):
> > ```
> >
> > The two new special methods would have the following prototypes:
> >
> > ```Python
> >     def __new_forward__(metaclass, name, bases, namespace, **kwargs):
> >
> >     def __new_continue__(metaclass, cls, **kwargs):
> > ```
> >
> > `__new_forward__` creates the class object.  It sets the `namespace`
> > member as the class dict, but in general should not examine it
> > contents.  (Specifically, `__new_forward__` cannot make any assumptions
> > about whether or not the class body has been executed yet; more on this
> > in a moment.)
> >
> > `__new_continue__` is guaranteed to be called after the
> > class body has been executed.
> >
> > The externally-visible parts of class construction would
> > run in a different order for classes constructed using
> > `forward class` and `continue class`.  First, the visible
> > interactions from the `forward class` statement:
> >
> > 1. Python calls `MetaClass.__prepare__`.
> > 2. Python calls `MetaClass.__new_forward__`.
> > 3. The `forward class` statement binds the (forward-declared)
> >    class object to the name `Foo`.
> >
> > And here are the visible interactions from the
> > `continue class` statement:
> >
> > 1. Python executes the class body.
> > 2. Python calls `MetaClass.__new_continue__`.
> > 3. Python calls `BaseClass.__init_subclass__`.
> >    (If multiple base classes define `__init_subclass__`,
> >    they're called in MRO order.)
> > 4. Python calls `MetaClass.__init__`.
> >
> > It's important to note that, while `namespace` is passed
> > in to `__new_forward__`, it's not yet initialized with the
> > class body.  It's passed in here because the "dict-like object"
> > returned by `MetaClass.__prepare__` is used as the `__dict__`
> > for the forward-declared class object.
> >
> > (This is also novel.  Normally the "dict-like object" is
> > used as the namespace for the class body, then its contents
> > are copied out and it is discarded.  Here it will also be
> > used as the `__dict__` for the forward-declared class object
> > until the `continue class` statement executes.)
> >
> > Splitting `__new__` into two methods in this manner has several
> > ramifications for existing code.
> >
> > First, Python still needs to support `MetaClass.__new__`
> > for backwards compatibility with existing code.  Therefore,
> > when executing the `class` statement, Python will still call
> > `MetaClass.__new__`.  In fact, for maximum backwards
> > compatibility, the order of externally-visible events
> > for the `class` statement should not change at all.
> >
> > The default implementation of `MetaClass.__new__` will be
> > changed to call `__new_forward__` and `__new_continue__`.
> > The implementation will be similar to the following
> > pseudo-code:
> >
> > ```Python
> >     def __new__(metaclass, name, bases, namespace, **kwargs):
> >         cls = metaclass.__new_forward__(metaclass, name, bases,
> > namespace, **kwargs)
> >         metaclass.__new_continue__(metaclass, cls, namespace, **kwargs)
> >         return cls
> > ```
> >
> > This means the order of events will be slightly different
> > between a class defined with the `class` statement and
> > a class defined with the `forward class` and `continue class`
> > statements.  With a `class` statement, the class body will be
> > run *before* `__new_forward__` is called, but with a `forward class`
> > statement, the class body will be run *after* `__new_forward__`
> > is called.  (This is why `__new_forward__` cannot know in advance
> > whether or not the class body has been called, and the `namespace`
> > has been filled in.)
> >
> > User code that defines its own metaclass with its own `__new__`
> > must also continue to work.  But this leads us to a dangerous
> > boundary condition:
> >   * if user code defines a metaclass, and
> >   * that metaclass defines `__new__` but not `__new_forward__` or
> >     `__new_continue__`, and
> >   * user code then uses that metaclass in a `forward class`
> >     declaration, then
> > Python must throw a `TypeError` exception.  This situation is
> > unsafe: clearly the intention with the user's metaclass is to
> > override some behavior in `__new__`, but the `forward new` statement
> > will never call `__new__`.
> >
> > (It's safe to use a metaclass with `forward class` if it doesn't
> > define `__new__`, or if it defines both `__new__` and either
> > `__new_forward__` or `__new_continue__`.  It's also safe to
> > use a metaclass with `class` if it defines either `__new_forward__`
> > or `__new_continue__` but not `__new__`, because the default `__new__`
> > will call both `__new_forward__` and `__new_continue__`.)
> >
> > Going forward, best practice for metaclasses would be to only
> > implement `__new_forward__` and `__new_continue__`.
> > Code with metaclasses that wanted to simultaneously support
> > versions of Python with these new dunder methods *and* older
> > versions of Python that predate this change would likely have
> > to conditionally define their own `__new__`, best practices
> > on this approach TBD.
> >
> > #### Interactions between `class`, `forward class`, and `continue class`
> >
> > `class` and `forward class` both bind a name to a newly-created object.
> > Thus, in the same way that you can have two `class` statements that
> > bind and re-bind the same name:
> >
> > ```Python
> >     class C:
> >         pass
> >     class C:
> >         pass
> > ```
> >
> > You can execute `class` and `forward class` statements in any order
> > to bind and re-bind the same name:
> >
> > ```Python
> >     class C:
> >         pass
> >     forward class C
> > ```
> >
> > This works as expected; when this code executes, the previous objects
> > are dereferenced, and only the last definition of `C` is kept.
> >
> > Executing a `continue class` statement with a class defined by the
> > `class` statement raises a `ValueError` exception.
> > Executing a `continue class` statement with a class defined by the
> > `forward class` statement that has already had `continue class`
> > executed on it raises a `ValueError` exception.
> >
> > It's expected that knowledgeable users will be able to trick
> > Python into executing `continue class` on the same class multiple
> > times by interfering with "dunder" attributes.  The same tricks
> > may also permit users to trick Python into executing `continue class`
> > on a class defined by the `class` statement.  This is undefined
> > and unsupported behavior, but Python will not prevent it.
> >
> >
> > Final Notes
> > -----------
> >
> > #### Alternate syntax
> >
> > Instead of `forward class`, we could use `def class`.  It's not as
> > immediately clear, which is why this PEP prefers `forward class`.
> > But this alternate syntax has the advantage of not adding a new
> > keyword to the language.
> >
> >
> > #### forward classes and PEP 649
> >
> > I suggest that `forward class` meshes nicely with PEP 649.
> >
> > PEP 649 solves the forward-reference and circular-reference
> > problem for a lot of use cases, but not all.  So by itself
> > it's not quite a complete solution to the problem.
> >
> > This `forward class` proposal should solve *all* the
> > forward-reference and circular-reference problems faced
> > by Python users today.  However, its use requires
> > backwards-incompatible code changes to user code.
> >
> > By adding both PEP 649 and `forward class` to Python, we
> > get the best of both worlds.  PEP 649 should handle most
> > forward-reference and circular-reference problems, but the
> > user could resort to `forward class` for the stubborn edge
> > cases PEP 649 didn't handle.
> >
> > In particular, combining this PEP with PEP 649 achieves total
> > coverage of the challenges cited by PEP 563's *Rationale* section:
> >
> > > * forward references: when a type hint contains names that have not
> > been
> > >   defined yet, that definition needs to be expressed as a string
> > literal;
> > > * type hints are executed at module import time, which is not
> > >   computationally free.
> >
> > PEP 649 solves many forward reference problems, and delays the evaluation
> > of annotations until they are used.  This PEP solves the remaining
> > forward
> > reference problems.
> >
> >
> > ### A proof-of-concept using decorators
> >
> > I've published a repo with a proof-of-concept of
> > the `forward class` / `continue class` syntax,
> > implemented using decorators.
> > It works surprisingly well, considering.
> > You can find the repo here:
> >
> >     https://github.com/larryhastings/forward
> >
> > Naturally, the syntax using this decorators-based version
> > can't be quite as clean.  The equivalent declaration for
> > `class X` using these decorators would be as follows:
> >
> > ```Python
> >     from forward import *
> >
> >     @forward()
> >     class X():
> >        ...
> >
> >     @continue_(X)
> >     class _:
> >        # class body goes here
> >        pass
> > ```
> >
> > Specifically:
> >
> > * You have to make the `forward` module available somehow.  You can
> > just copy the
> >   `forward` directory into the directory you want to experiment in, or
> > you can
> >   install it locally in your Python install or venv by installing the
> > `flit`
> >   package from PyPI and running `flit install -s` .
> > * You must import and use the two decorators from the `forward` module.
> >   The easiest way is with `from forward import *` .
> > * For the `forward class` statement, you instead decorate a
> > conventional class
> >   declaration with `@forward()`.  The class body should be empty, with
> > either
> >   a single `pass` statement or a single ellipsis `...` on a line by
> > itself;
> >   the ellipsis form is preferred.  You should name this class with the
> > desired
> >   final name of your class.
> > * For the `continue class` statement, you instead decorate a conventional
> >   class declaration with `@continue_()`, passing in the
> > forward-declared class
> >   object as a parameter to the decorator.  You can use the original
> > name of
> >   the class if you wish, or a throwaway name like `_` as per the example.
> > * You may use additional decorators with either or both of these
> > decorators.
> >   However it's vital that `@forward()` and `@continue_()` are the
> >   *first* decorators run--that is, they should be on the *bottom* of the
> >   stack of decorators.
> >
> > Notes and caveats on the proof-of-concept:
> >
> > * The `continue_` decorator returns the original "forwarded" class
> > object.
> >   This is what permits you to stack additional decorators on the class.
> >   (But, again, you *must* call the `continue_` decorator first--it should
> >   be on the bottom.)
> > * To use `__slots__`, you will have to declare them in the `forward`
> > class.
> > * The proof-of-concept can't support classes that inherit from a class
> >   which defines `__init_subclass__`.
> > * Like the proposed syntax, this proof-of-concept doesn't support
> >   decorators that both examine the contents of the class *and* return
> >   a different object, e.g. `@dataclass(slots=True)` in Python 3.10.
> > * This proof-of-concept doesn't work with metaclasses that
> >   override either `__new__` or `__init__`, where those functions
> >   examine the `namespace` argument in any meaningful way.
> >
> >
> > #### tools/
> >
> > There are some tools in the `tools/` directory that will (attempt to)
> > automatically add or remove the `@forward()` decorator to class
> > definitions
> > in Python scripts.  It turns this:
> >
> > ```Python
> >     class foo(...):
> >         pass
> > ```
> >
> > into this:
> >
> > ```Python
> >     @forward()
> >     class foo(...):
> >         ...
> >
> >     @continue_(foo)
> >     class _____:
> >         pass
> > ```
> >
> > `tools/edit_file.py` will edit one or more Python files specified on the
> > command-line, making the above change.  By default it will toggle the
> > presence of `@forward`
> > decorators.  You can also specify explicit behavior:
> >
> > `-a` adds `@forward()` decorators to `class` statements that don't
> > have them.
> > `-r` removes `@forward` decorators, changing back to conventional
> > `class` statements.
> > `-t` requests that it "toggle" the state of `@forward()` decorators.
> >
> > The parser is pretty dumb, so don't run it on anything precious. If it
> > goofs up, sorry!
> >
> > `tools/edit_tree.py` applies `edit_py.py` to all `*.py` files found
> > anywhere under
> > a particular directory.
> >
> > `tools/edit_stdlib.py` was an attempt to intelligently apply
> > `edit_file.py` to the `Lib`
> > tree of a CPython checkout.  Sadly, the experiment didn't really work
> > out; it seemed
> > like there were so many exceptions where the brute-force modification
> > didn't work,
> > either due to descriptors, metaclasses, or base classes with
> > `__init_subclass__`,
> > that I gave up on the time investment.  It's provided here in a
> > non-functional
> > state in case anyone wants to experiment with it further.
> >
> > Also, it's intentionally delicate; it only works on git checkout
> > trees, and only with
> > one specific revision id:
> >
> >     7b87e8af0cb8df0d76e8ab18a9b12affb4526103
> >
> > #### Postscript
> >
> > Thanks to Eric V. Smith and Barry Warsaw for proofreading and ideas.
> > Thanks in particular to Eric V. Smith for the idea about making
> > `__slots__` processing lazy.
> > Thanks to Mark Shannon for the idea of prototyping `forward class`
> > and `continue class` using decorators and simply copying the
> > attributes.
> >
> >
> > _______________________________________________
> > 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/CW6Z3OS42DYNMO4Y42R6O3LVTPPAA57X/
> > Code of Conduct: http://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/WSJGXGVOIWUAQWEJ2GAAAL3QT2BJ46K3/
> Code of Conduct: http://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/PLA3ARS3XDMIBOUJFI3D3RJN3ZJTMNWS/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to