[Python-Dev] Re: Pattern matching reborn: PEP 622 is dead, long live PEP 634, 635, 636

2020-11-02 Thread Brett Cannon
On Fri, Oct 30, 2020 at 6:39 PM Tin Tvrtković  wrote:

> A small update on this, since I've been playing with it.
>
> I'm trying to implement a websocket proxy, since it's an example of a toy
> project that needs to juggle two long-lived asyncio connections at once.
> I'm using Starlette/Uvicorn for the server part (the part that accepts the
> connection) and aiohttp's client functionality to connect to an echo server
> on the Internet.
>
> I've settled on the async iterator interface as a good building block for
> this, not queues. Turns out an async iterator looks very much as the read
> interface for a Go channel (they spit out values and signal their closure).
> Aiohttp already provides an async iterator interface for reading from the
> upstream server. Starlette doesn't, but an adapter is very easy to write.
>
> Now that we've settled on a suitable interface, a helper function
> (wait_on) is easy to write. (Code omitted for brevity.) This is the entire
> request handler:
>
> async def ws_proxy(client: WebSocket):
> await client.accept()
> async with ClientSession() as session:
> async with session.ws_connect("wss://echo.websocket.org") as s:
> c = starlette_websocket_iterator(client)
> async for r in wait_on(c, s):
> match r:
> case (src, None):
> print(f"{src} closed the connection")
> break
> case (src, msg) if src is c:
> print(f"CLIENT: {msg}")
> await s.send_str(msg)
> case (src, msg) if src is s:
> print(f"SERVER: {msg}")
> await client.send_text(msg.data)
>

To compare against the non-match approach:

async for src, msg in wait_on(c, s):
if msg is None:
print(f"{src} closed the connection")
break
elif src is c:
print(f"CLIENT: {msg}")
await s.send_str(msg)
elif src is s:
print(f"SERVER: {msg}")
await client.send_text(msg.data)

-Brett


>
> So yeah, the helper yields tuples of the source and message, using None as
> a sentinel for closure. Guards are used to match on the source, using
> iterator identity. My first version just used `case (s, msg):` hoping to
> match on the identity of s, but that doesn't work since s is not a literal.
>
> I'd say this is pretty cool. With the ecosystem moving to async iterators
> for streams of data (or just writing adapters), I'd say this style of
> programming is quite readable and understandable.
>
> On Tue, Oct 27, 2020 at 1:16 AM Tin Tvrtković 
> wrote:
>
>> Hello,
>>
>> Go channels are indeed very similar to asyncio Queues, with some added
>> features like channels being closable. (There is also special syntax in the
>> select statement, `val, ok <- chan`, that will set the `ok` variable to
>> false if the channel has been closed.) A larger difference, I think, is
>> that in Go channels are used practically everywhere, more so than asyncio
>> Queues. They are an abstraction the vast majority of Go concurrency is
>> built upon.
>>
>> Building this for asyncio tasks, instead of just queues, would be much
>> more useful in Python.
>>
>> Contemplating this some more, I would agree we don't need an async match.
>> A function and some types to match on would probably be enough to get us
>> close to a select statement in a PEP634 Python. I guess the challenge is
>> designing these matchable types for ease of use now, and I need to study
>> the pattern matching PEPs in more detail to be able to contribute here.
>>
>> On one hand, this means this problem can be solved by a third party
>> library. On the other hand, I feel like this would be very useful so it
>> might be worth it to have it somewhere in the stdlib asyncio namespace.
>>
>> Since `asyncio.wait` can yield multiple tasks in the completed set, this
>> would probably have to be wrapped in an `async for`.
>>
>>
>>
>> On Mon, Oct 26, 2020 at 12:33 PM Gustavo Carneiro 
>> wrote:
>>
>>> It's true that asyncio.wait provides the tools that you need, but it's a
>>> bit clunky to use correctly.
>>>
>>> Maybe would be something along the lines of:
>>>
>>> --
>>> queue1 = asyncio.Queue()
>>> queue2 = asyncio.Queue()
>>> ...
>>> get1 = asyncio.create_task(queue1.get())
>>> get2 = asyncio.create_task(queue2.get())
>>> await asyncio.wait({get1, get2}, return_when=asyncio.FIRST_COMPLETED)
>>> match [task.done() for task in (get1, get2)]:
>>> case [True, False]:  get2.cancel(); item1 = await get1; 
>>> case [False, True]:  get1.cancel(); item2 = await get2; 
>>> case [True, True]:  item1 = await get1; ; item2 = await get2;
>>> 
>>> --
>>>
>>> If asyncio.Queue() is the equivalent of Go channels, perhaps it would be
>>> worth designing a new API for asyncio.Queue, one that is better suited to
>>> the match statement:
>>>
>>> class Queue:
>>>async def read_wait(self) 

[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Greg Ewing

On 3/11/20 11:01 am, Ethan Furman wrote:


I believe supporting

     case x, x   # look ma!  no guard!

is a possible future enhancement.


In which case there will be a need for *some* kind of true
"don't care" placeholder. If it's not "_" then it will have
to be something else like "?". And we need to decide about
it now, because once people start using "_" as a wildcard
in patterns, it will be too late to go back.

--
Greg
___
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/CIMR47FNVET4427SUXYWM46LGRAO7JQH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Chris Angelico
On Tue, Nov 3, 2020 at 8:53 AM Glenn Linderman  wrote:
>
> On 11/2/2020 1:42 PM, Guido van Rossum wrote:
> > But we feel that `case x, x` can easily be misunderstood as "a tuple
> > of two equal values"
>
> So what _is_ the syntax for "a tuple of two equal values" ?
>
> case x, ?x:  # comes to mind (not that it is in the PEP :))

case x, y if x == y:

If it gets a lot of demand, a dedicated syntax can be added in the
future without breaking anything.

ChrisA
___
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/574IVLKJKR2JF455MRRHUH23V7HEXX4I/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Ethan Furman

On 11/2/20 1:52 PM, Glenn Linderman wrote:

On 11/2/2020 1:42 PM, Guido van Rossum wrote:

But we feel that `case x, x` can easily be misunderstood as "a tuple of two equal 
values"


So what _is_ the syntax for "a tuple of two equal values" ?

case x, ?x:  # comes to mind (not that it is in the PEP :))


Using a guard statement:

case x, y if x == y

I believe supporting

case x, x   # look ma!  no guard!

is a possible future enhancement.

--
~Ethan~
___
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/HA2YAGKS6FY63E3MLDDCAC7FNWA77T7Q/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Brandt Bucher
Glenn Linderman wrote:
> So what _is_ the syntax for "a tuple of two equal values" ?

If you’re asking about PEP 634:

```
case x, y if x == y:
```

Which is much clearer, in my opinion.
___
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/UM6ZACEZLF2B6YLMMO4TASWCVVKD2KPM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Glenn Linderman

On 11/2/2020 1:42 PM, Guido van Rossum wrote:
But we feel that `case x, x` can easily be misunderstood as "a tuple 
of two equal values"


So what _is_ the syntax for "a tuple of two equal values" ?

case x, ?x:  # comes to mind (not that it is in the PEP :))
___
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/GPSLYBPMXRFQHUST7CYTI6LNJY7D25EH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Guido van Rossum
On Mon, Nov 2, 2020 at 1:14 PM Eric V. Smith  wrote:

> On 11/2/2020 9:31 AM, Thomas Wouters wrote:
>
>
>
> On Sat, Oct 31, 2020 at 12:25 PM Steven D'Aprano 
> wrote:
>
>>
>> I really don't get why so many people are hung up over this minuscule
>> issue of giving `_` special meaning inside match statements. IMO,
>> consistency with other languages' pattern matching is more useful than
>> the ability to capture using `_` as a variable name.
>>
>
> Allow me to explain, then: structured pattern matching is (even by
> admission of PEPs 634-363) an extension of iterable unpacking. The use of
> '_' as a wildcard pattern is a sharp break in that extension. In the
> structured pattern matching proposal, '_' is special syntax (and not in any
> way less so than '?') but *only* in cases in match statements, not in
> iterable unpacking. It *already* isn't consistent with '_' in other
> languages, and we can't fix that without breaking uses of _ for gettext,
> not to mention other situations existing code uses '_' as something other
> than an assign-only variable.
>
> Using '_' in structured pattern matching means any use of '_' becomes an
> extra burden -- you have to know whether it's a name or not based on the
> surrounding context. It makes all uses of '_' harder to parse, and it makes
> it easier to mistake one situation for another. Perhaps not terribly easy,
> but since there is _no_ confusion now, it's by definition *easier*. The use
> of something else, like '?', leaves existing uses of '_' unambiguous, and
> allows structured pattern matching and iterable unpacking to be thought of
> the same. It reduces the complexity of the language because it no longer
> uses the same syntax for disparate things.
>
> All good points.
>
> What I don't understand is why '_' is treated any differently than any
> named capture pattern. It seems to me that using:
>
> case x:# a capture_pattern
>
> is the same as:
>
> case _:  # the wildcard_pattern
>
> They both always match (I'm ignoring the binding thing here, it's coming
> up). I realize PEP 635 gives the rational for separating this so that it
> can enforce that "case x, x:" can be made invalid, likening it to duplicate
> function parameters. The PEP focuses on the differences between that and
> tuple unpacking. But I think that if the semantics were the same as tuple
> unpacking (allowed duplicates, and binding to the last one) then the whole
> "_ as wildcard" arguments would just go away, and "_" would be treated just
> as it is elsewhere in Python. For me, this would address Thomas' point
> above and reduce the cognitive load of having a special rule.
>
> But I'm probably missing some other nuance to the whole discussion, which
> will no doubt now be pointed out to me.
>
> Eric
>

That's not an unreasonable characterization. But we feel that `case x, x`
can easily be misunderstood as "a tuple of two equal values" and we want to
be able to call that out as an error. Hence the need for recognizing the
wildcard in the parser, since `case x, _, _` *is* important. Hence the need
to standardize it (i.e., not leave it to be *just* a convention). Using _
seems the most commonly used convention for "throwaway" target (although we
know some organizations have different conventions), *and* it matches the
wildcard notation in most other languages, which looks like a win-win to
me. Finally, not assigning a value to _ is kind of important in the context
of i18n, where _("string") is the common convention for tagging
translatable strings.

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

___
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/IBLA5FZB7LBKHCZME3ABG2GV722UCYAL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Eric V. Smith

On 11/2/2020 9:31 AM, Thomas Wouters wrote:



On Sat, Oct 31, 2020 at 12:25 PM Steven D'Aprano > wrote:



I really don't get why so many people are hung up over this minuscule
issue of giving `_` special meaning inside match statements. IMO,
consistency with other languages' pattern matching is more useful
than
the ability to capture using `_` as a variable name.


Allow me to explain, then: structured pattern matching is (even by 
admission of PEPs 634-363) an extension of iterable unpacking. The use 
of '_' as a wildcard pattern is a sharp break in that extension. In 
the structured pattern matching proposal, '_' is special syntax (and 
not in any way less so than '?') but *only* in cases in match 
statements, not in iterable unpacking. It *already* isn't consistent 
with '_' in other languages, and we can't fix that without breaking 
uses of _ for gettext, not to mention other situations existing code 
uses '_' as something other than an assign-only variable.


Using '_' in structured pattern matching means any use of '_' becomes 
an extra burden -- you have to know whether it's a name or not based 
on the surrounding context. It makes all uses of '_' harder to parse, 
and it makes it easier to mistake one situation for another. Perhaps 
not terribly easy, but since there is _no_ confusion now, it's by 
definition *easier*. The use of something else, like '?', leaves 
existing uses of '_' unambiguous, and allows structured pattern 
matching and iterable unpacking to be thought of the same. It reduces 
the complexity of the language because it no longer uses the same 
syntax for disparate things.



All good points.

What I don't understand is why '_' is treated any differently than any 
named capture pattern. It seems to me that using:


case x:    # a capture_pattern

is the same as:

case _:  # the wildcard_pattern

They both always match (I'm ignoring the binding thing here, it's coming 
up). I realize PEP 635 gives the rational for separating this so that it 
can enforce that "case x, x:" can be made invalid, likening it to 
duplicate function parameters. The PEP focuses on the differences 
between that and tuple unpacking. But I think that if the semantics were 
the same as tuple unpacking (allowed duplicates, and binding to the last 
one) then the whole "_ as wildcard" arguments would just go away, and 
"_" would be treated just as it is elsewhere in Python. For me, this 
would address Thomas' point above and reduce the cognitive load of 
having a special rule.


But I'm probably missing some other nuance to the whole discussion, 
which will no doubt now be pointed out to me.


Eric

___
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/URM22DOSDT7YKI4HFR2ACKY3K3HTHYZP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Drop Solaris, OpenSolaris, Illumos and OpenIndiana support in Python

2020-11-02 Thread Jakub Kulík
Hi, that was me fixing Oracle Solaris related issues.

To be completely honest, I wasn't sure if you would be interested in some
of our patches, because I thought that Python works without issues on
Illumos based systems and our patches might be very Oracle Solaris
specific. It seems that I was wrong (especially if I am the only one making
more Solaris fixes) - and looking at the OpenIndiana repo confirms that
suspicion because their Python 3.7 is almost exact copy of our repo with
the same patches fixing the same issues.

I am more than happy to help with Solaris related Python development. It
seems like Illumos is still pretty similar, hitting the same issues, so we
don't have to be afraid that fixes for one will break the other (especially
once/if Illumos build bot will be available). I will do more of those first
three points you mentioned and also upstream more of our patches, of which
we have several (
https://github.com/oracle/solaris-userland/tree/master/components/python/python39/
).

Also, as mentioned in the bug tracker, we are looking at how to provide
build bots running on Oracle Solaris.

Jakub

pá 30. 10. 2020 v 13:54 odesílatel Victor Stinner 
napsal:

> Hi Ronald,
>
> Le ven. 30 oct. 2020 à 12:59, Ronald Oussoren  a
> écrit :
> > I agree. That’s what I tried to write, its not just providing a buildbot
> but also making sure that it keeps working and stays green.
>
> This is really great!
>
> Jesús Cea Avión is also a volunteer to maintain the Solaris (see the bpo).
>
> Moreover, it seems like some people would like to provide servers to
> run a Solaris buildbot. Example:
> https://bugs.python.org/issue42173#msg379895
>
> Two volunteer core developers and at least one buildbot would help a
> lot to ensure that Python is working on Solaris for real, and reduce
> the number of open Solaris issues. If it happens, I'm perfectly fine
> with keeping Solaris support.
>
> I also hope that more people will contribute to maintain the code, not
> only Ronald and Jesús. Many people wrote to me that Python is a key
> component of Illumos (the package manager is written in Python). So
> maybe Python on Illumos deserves some love?
>
> There are many ways to contribute to the Solaris support of Python:
>
> * Comment Solaris issues (bugs.python.org, search for "Solaris" in the
> title)
> * Propose PRs to fix issues or implement Solaris specific features
> * Review Solaris PRs
> * Provide Solaris servers accessible to Python core developers (SSH access)
> * Donate to the CPython project:
>
>   * https://www.python.org/psf/donations/python-dev/
>   * https://github.com/sponsors/python
>
> * etc.
>
> See also the https://devguide.python.org/ if you would like to
> contribute to Python.
>
> By the way, thanks Jakub Kulík (CC-ed to this email) who fixed
> multiple Solaris issues in the last 2 years ;-)
>
> Victor
> --
> Night gathers, and now my watch begins. It shall not end until my death.
>
___
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/EWCEFLLXSL2LSXDSLD73TOWHVWK2EPTH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Thomas Wouters
On Sat, Oct 31, 2020 at 12:25 PM Steven D'Aprano 
wrote:

>
> I really don't get why so many people are hung up over this minuscule
> issue of giving `_` special meaning inside match statements. IMO,
> consistency with other languages' pattern matching is more useful than
> the ability to capture using `_` as a variable name.
>

Allow me to explain, then: structured pattern matching is (even by
admission of PEPs 634-363) an extension of iterable unpacking. The use of
'_' as a wildcard pattern is a sharp break in that extension. In the
structured pattern matching proposal, '_' is special syntax (and not in any
way less so than '?') but *only* in cases in match statements, not in
iterable unpacking. It *already* isn't consistent with '_' in other
languages, and we can't fix that without breaking uses of _ for gettext,
not to mention other situations existing code uses '_' as something other
than an assign-only variable.

Using '_' in structured pattern matching means any use of '_' becomes an
extra burden -- you have to know whether it's a name or not based on the
surrounding context. It makes all uses of '_' harder to parse, and it makes
it easier to mistake one situation for another. Perhaps not terribly easy,
but since there is _no_ confusion now, it's by definition *easier*. The use
of something else, like '?', leaves existing uses of '_' unambiguous, and
allows structured pattern matching and iterable unpacking to be thought of
the same. It reduces the complexity of the language because it no longer
uses the same syntax for disparate things.

-- 
Thomas Wouters 

Hi! I'm an email virus! Think twice before sending your email to help me
spread!
___
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/QV6TA57FTMAKFPFDMPGN4RH65M7CWM4R/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Nick Coghlan
On Sun, 1 Nov 2020 at 11:29, Nick Coghlan  wrote:
> On Sat., 31 Oct. 2020, 9:29 pm Steven D'Aprano,  wrote:
>> (4) Patterns which could conceivably be interpreted as assignment
>> targets default to capture patterns, because that's what is normally
>> wanted in pattern matching:
>>
>>
>> case [1, spam, eggs]:
>> # captures spam and eggs
>>
>>
>> If you don't want to capture a named value, but just match on it,
>> override it with an explicit `==` or `is`:
>>
>>
>> case [1, ==spam, eggs]:
>> # matches `spam` by equality, captures on eggs
>
>
> As noted above, the current PEP 634 spec doesn't allow this, but if it did, 
> then I agree it would adress most of the concerns that prompted me to write 
> PEP 642.
>
> If the 634 PEP authors are amenable, I'd be happy to prepare a PR against the 
> PEP that made this change so you could see what it would look like at the 
> grammar level.

Since Guido has indicated he's still dubious about the value of
offering an explicit prefix marker syntax at all, I'm instead going to
agree with most of Steven's counter proposal and adopt it as the next
iteration of PEP 642 (conceding the point on "_", using "==" and "is"
as the prefix markers, and keeping the syntactic sugar that lets you
omit the "==" prefix for comparison against literals and attributes).

For the literal comparisons where equality isn't the right default,
I'm still proposing leaving out the special casing, but I'm switching
to proposing that we just not consider them valid literals for pattern
matching purposes in the initial iteration of the design (so `is None`
would be allowed as an identity constraint, but a bare ``None`` would
be rejected as ambiguous, at least for now. I'd be more prepared to
concede the "But is it *really* ambiguous?" case for `None` and `...`
than I would for `True` and `False`, though).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
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/OAIWD6UFYMKIUB7O5LLVLAZJO2R2QX5G/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

2020-11-02 Thread Nick Coghlan
On Sun., 1 Nov. 2020, 3:01 pm Guido van Rossum,  wrote:

> On Sat, Oct 31, 2020 at 21:48 Dan Stromberg  wrote:
>
>>
>> On Sat, Oct 31, 2020 at 9:37 PM Guido van Rossum 
>> wrote:
>>
>>>
>>> I think this over-stresses the notion that users might want to override
>>> the comparison operator to be used. We only have two operators that make
>>> sense in this context, 'is' and '==', and really, for almost everything you
>>> want to do, '==' is the appropriate operator. (There is a small trickle of
>>> bugs caused by people inappropriately using e.g. `if x is 1` instead of `if
>>> x == 1`, suggesting that if anything, there is too much freedom here.) The
>>> big exception is `None`, where you basically always want to use `is`, which
>>> is what PEP 634 does.
>>>
>>
> FWIW, there's an additional exception:
>> sentinel = object()
>>
>> if var is sentinel:
>>
>> I use this idiom from time to time - instead of None.
>>
>
> You can just write ‘case sentinel’, since object’s == operator uses
> identity anyway.
>

No, you can't, as the other operand might decide it wants to compare equal
to your sentinel value.

Cheers,
Nick.


-- 
> --Guido (mobile)
>
___
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/OSBJP7UTG6VFROJSS5ORKHXYOUZYVCKD/
Code of Conduct: http://python.org/psf/codeofconduct/