Re: [Python-ideas] Logging Levels

2017-11-28 Thread Nick Coghlan
On 29 November 2017 at 06:46, Mike Miller <python-id...@mgmiller.net> wrote:
> Hi, the reason I use note is that I want it to be output by default.  So it
> must be above warning, or perhaps the default level changed.

If the message to be displayed is part of the actual UX of a command
line tool, our advice is "You don't want the logging module, you want
the print() builtin":
https://docs.python.org/3/howto/logging.html#when-to-use-logging

As a relevant technical detail, it's also worth noting that the
default handler emits messages on stderr, while CLI UX messages should
generally be displayed on stdout.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Repurpose `assert' into a general-purpose check

2017-11-28 Thread Nick Coghlan
On 29 November 2017 at 02:03, Ivan Pozdeev via Python-ideas
<python-ideas@python.org> wrote:
> On 28.11.2017 16:36, Nick Coghlan wrote:
>> I'll make the same observation I usually do each time one of these
>> threads comes up:
>>
>> * I'm opposed to making assert substantially different from the way it
>> works now
>> * I'm in favour of adding a new "ensure()" builtin that encapsulates
>> the check-and-raise logic
>>
>> The reasons I prefer this approach:
>>
>> - assert is a statement *solely* so that the compiler can optimise it
>> out. If it's not optional,
>>it doesn't need to be a statement any more
>
> Another benefit of a statement vs function is only evaluating the
> error-related arguments when there's an error

If you're worried about that level of micro-optimisation, it's
straightforward enough to write your own wrapper function that accepts
the components needed to build a suitably formatted message. There's
no need to make the builtin more complicated to cope with it (that
smooth transition from the builtin behaviour to customised behaviour
is one of the other advantages of using a plain function).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Repurpose `assert' into a general-purpose check

2017-11-28 Thread Nick Coghlan
On 28 November 2017 at 15:41, Steven D'Aprano <st...@pearwood.info> wrote:
> On Tue, Nov 28, 2017 at 05:12:36AM +0300, Ivan Pozdeev via Python-ideas wrote:
>> Unlike C, Python does the aforementioned checks all the time, i.e. it's
>> effectively always in "debug mode".
>
> Apart from -O which disables assertions. But in any case, the best use
> of assertions is not checking things which the interpreter is going to
> do anyway, but checking things which the interpreter can not and does
> not check automatically: your program logic. There is no way that the
> Python interpreter is going to do this check automatically, unless I
> write the assertion:
>
> assert 0 <= r < abs(y)
>
> That is copied straight out of one of my functions.

I'll make the same observation I usually do each time one of these
threads comes up:

* I'm opposed to making assert substantially different from the way it works now
* I'm in favour of adding a new "ensure()" builtin that encapsulates
the check-and-raise logic

The reasons I prefer this approach:

- assert is a statement *solely* so that the compiler can optimise it
out. If it's not optional,
  it doesn't need to be a statement any more
- if the existing assert statements are left alone, there are no
performance or compatibility
  concerns for folks that rely on the current behaviour
- if it's a function, it doesn't need to be called "assert", it can use the more
  imperative term "ensure" (meaning "ensure this condition is true
before continuing")
- if it's a function, it can easily be emulated on old versions via
compatibility libraries
- "ensure() is required, assert is optional" is a better answer to
complaints about
  assertions being optional than suggesting "if cond: raise AssertionError(msg)"
  as a reasonable alternative to "assert cond, msg"
- if it's a function, we get access to all the regular function
machinery, so we're
  not restricted to positional-only arguments the way the assert statement is

My initial proposed behaviour for the function:

def ensure(cond, msg=None, exc_type=RuntimeError):
"""Raise an exception if the given condition is not true"""
if not cond:
if msg is None:
frame = sys._getframe(1)
line = frame.f_lineno
modname = frame.f_globals.get("__name__", "")
msg = f"Condition not met on line {line:d} in {modname!r}"
raise exc_type(msg)

Cheers,
Nick.

P.S. No, I'm not offering to write that PEP myself, I'd just be in
favour of the idea if someone else were to write it :)

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Using an appropriate tone in emails (was: Adding a thin wrapper class around the functions in stdlib.heapq)

2017-11-28 Thread Nick Coghlan
On 28 November 2017 at 13:22, bunslow <buns...@gmail.com> wrote:
> My first submission to this list was predicated on what I'd read in PEPs --
> and many of those, since they recommend major-enough changes to require a
> PEP, have sections (often lengthy) dedicated to "what's wrong with the
> status quo". My attempt to imitate that obviously crossed some boundaries in
> retrospect, and of course now that it's brought up here I see that spinning
> it as "what can be done to make it better" is psychologically much more
> effective than "why the current way sucks" (because semantically these are
> either approximately or exactly the same). But that's where it came from, at
> least with some of my earlier threads, and I suspect the author of the topic
> message of the OP will have a similar sentiment.

Yeah, by the time someone reaches the point of writing a PEP, there's
usually some level of existing awareness along the lines of "The
status quo might not be OK any more, so let's explicitly document the
risks and benefits associated with a possible change".

That means part of the role of the PEP is to summarise the relevant
problems with the status quo, such that future readers can understand
why any change is being proposed at all.

In cases where the proposed change is relatively simple at a technical
level, like PEP 479 (converting an unhandled StopIteration to
RuntimeError), PEP 538 (coercing the C locale to a UTF-8 based
locale),  or PEP 565 (tweaking the way we handle DeprecationWarning),
the motivation & rationale may end up being the majority of the PEP,
since the actual change to be made is relatively minor, but the
potential consequences aren't necessarily obvious.

By contrast, python-ideas threads usually start at a point earlier in
the decision making process: asking ourselves the question "Is the
status quo still OK?". In most cases the answer is "Yeah, it's still
fine", but we keep asking, because sometimes the answer is "Actually,
we could probably improve it by doing...".

The easiest trap to fall into on that front is to think to ourselves
"The status quo doesn't solve my problems, therefore it doesn't solve
anyone's problems", which usually isn't a productive mindset.

A more productive framing is typically "The problems that the status
quo solves are not the problems that I currently have".

It may seem like a small change, but in the second version, we're thinking:

- the status quo solves problems for someone, just not for me
- whatever I propose should try to avoid making the status quo worse
at what it already does
- I need to explain the problem I have, not just the potential solution I see

and that ends up coming through in the way we write.

I'll also note that nobody expects perfection on this front - most of
us are thoroughly familiar with the lure of "But someone is *wrong* on
the internet" [1], and we know that sometimes it's too late by the
time we finally think "Oh, I really should have toned that down a bit
before hitting Send...". We just strive to ensure our typical approach
is to be respectful of each other, and of past contributors.

Cheers,
Nick.

[1] https://xkcd.com/386/

P.S. For a longer version of the "What problem does it solve?"
question in relation to the respective APIs of the requests and urllib
modules, folks may be interested in
https://www.curiousefficiency.org/posts/2016/08/what-problem-does-it-solve.html

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] generator vs iterator etc. (was: How assignment should work with generators?)

2017-11-28 Thread Nick Coghlan
On 28 November 2017 at 16:11, Stephen J. Turnbull
<turnbull.stephen...@u.tsukuba.ac.jp> wrote:
> Steven D'Aprano writes:
>
>  > The subset of iterators which are created as generators are *also*
>  > called generators,
>
> As long as we're being precise, I don't think that is precisely correct:
>
> >>> (x for x in range(1))
>  at 0x10dee5e08>
> >>> iter(range(1))
> 
> >>> iter((1,))
> 
>
> The two iterators have the same duck-type, the generator is different.
> A generator (object) is, of course, an interable.

While it's not obvious with the genexp (since they're anonymous), the
main reason for the difference in the repr layouts here is just
because generator iterators can have names:

>>> def g(): yield
...
>>> g()


So the statement that "generator iterators are iterators" is correct.

The functions that create them are called generator functions because
they really are functions:

>>> g


What's more unfortunate here is that the usage of "generator" in the
generator-iterator representation doesn't actually align with the
preferred terminology in the documentation:
https://docs.python.org/3/glossary.html#term-generator

So I can understand the confusion here.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Adding a thin wrapper class around the functions in stdlib.heapq

2017-11-23 Thread Nick Coghlan
On 23 November 2017 at 17:13, Grant Jenks <grant.je...@gmail.com> wrote:

> And it will work! The heap algorithm is exposed through a high-level
> functional interface so that you can take advantage of duck-typing. This is
> an important Python feature.
>

Nobody is proposing taking the functional interface away (just as nobody is
proposing to take the bisect module away).

Instead, the argument is:

- the heapq functions need to be combined with concrete storage to be useful
- a simple wrapper class that combines them with a given list (or other
mutable sequence) is short and easy to maintain
- such a wrapper class is also useful in its own right for basic heap use
cases
- so let's provide one in the collections module

The potential arguments against that are:

- this means yet-another-data-type in the collections module, so it will
make the collections module harder to learn
- people will be confused as to whether they should use collections.Heap or
the heapq functions

The risks of both of those outcomes seem low, since the main current source
of confusion appears to be folks looking for a concrete "Heap" container
type, and being surprised when they get told they either need to be build a
DIY one from a list + the heapq functions, or else install a 3rd party
dependency to get a preassembled one.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Allow additional separator character in variables

2017-11-22 Thread Nick Coghlan
On 23 November 2017 at 16:34, Stephen J. Turnbull <
turnbull.stephen...@u.tsukuba.ac.jp> wrote:

> Nick Coghlan writes:
>
>  > We're not going to start second-guessing the Unicode Consortium on this
>  > point - human languages are complicated, and we don't have any special
>  > insight on this point that they don't.
>
> Agreed.  Python, however, is NOT a (natural) human language, and the
> Unicode Consortium definition of conformance does NOT prohibit
> subsetting appropriate to the purpose.  We DO know more than the
> Unicode Consortium about Python.  For example, I suspect that your
> catholic appetite for XID in identifiers does not apply to syntactic
> keywords or names of builtins.
>

We already have a stricter ASCII-only naming policy for the standard
library: https://www.python.org/dev/peps/pep-3131/#policy-specification

That's different from placing additional constraints on end-user code,
though, as that's where the line between "programming language" and
"natural language" gets blurry (variable, function, attribute, and method
names are often nouns and verbs in the author's language, and this is also
the case for data-derived APIs like pandas column names)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Adding a thin wrapper class around the functions in stdlib.heapq

2017-11-22 Thread Nick Coghlan
On 23 November 2017 at 15:22, bunslow <buns...@gmail.com> wrote:

> Something *should* be object oriented with the functions in question all
> operate on the same data type, and in particular, those functions/verbs
> *are only well defined for that type*. heapq.heappush(list-not-heap, item)
> is perfectly valid code in the current interface, but doesn't make any
> sense at all. And list.sort is *not* function based, it's an object
> oriented method. sorted() provides the same functionality for other types,
> given that it's a well defined function for a wide variety of sequences
> (unlike heappush). (list.sort is a method because unlike sorted(), it
> operates inplace, and is thus only meaningful for mutable, "complete" (all
> in memory, not "lazy") sequences -- i.e., a list.)
>
> I've never used bisect, so I'll refrain from commenting on it.
>
> At the end of the day, the patch proposed is merely a wrapper around the
> functional approach; you are welcome to continue using it as you like, it's
> not going anywhere. I would propose that the docs put the OOP version first
> though.
>

Ensuring the docs are clearly separated is part of why I think
"collections.Heap" would make more sense as a proposal than "heapq.Heap" -
collections already imports heapq for use in the Counter implementation,
and adding another primitive container type to collections is a smaller
conceptual change than updating heapq to being more than just a heap
algorithm library.

I'd also note that a collections.Heap class that accepts the underlying
list to use as its sole parameter would compose nicely with the list
builtin to allow creation of a heap from an arbitrary iterable:

heap = collections.Heap(list(iterable))

rather than the current:

heap = list(iterable)
heapq.heapify(heap)

That's akin to the difference between:

data = sorted(iterable)

and:

data = list(iterable)
data.sort()

I don't think it would be a disaster if we continued to leave this out, but
I don't think it would be a major maintenance burden or future barrier to
learning to add it, either.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Allow additional separator character in variables

2017-11-22 Thread Nick Coghlan
On 21 November 2017 at 21:55, Stephen J. Turnbull <
turnbull.stephen...@u.tsukuba.ac.jp> wrote:

> Personally, I think that Python probably should ban non-ASCII
> non-letter characters in identifiers and whitespace, and maybe add
> them later in response to requests from native speakers of the
> relevant languages.  I don't know how easy that would be to do,
> though, since I think the rule is already that identifiers must be
> composed only of letters, numbers, and ASCII "_".  Since Serhiy's
> examples are valid, we'd have to rule them out explicitly, rather than
> by reference to the Unicode database.  Yuck.
>

We're not going to start second-guessing the Unicode Consortium on this
point - human languages are complicated, and we don't have any special
insight on this point that they don't.
https://www.python.org/dev/peps/pep-3131/#specification-of-language-changes
delegated this aspect of the language to them by way of the XID_Start and
the XID_Continue categories, and we're not going to change that.

Any hybrid Python 2/3 application or library is necessarily restricted to
ASCII-only identifiers, since that's all that Python 2 supports.

We've also explicitly retained the ASCII-only restriction for PyPI
distribution names (see https://www.python.org/dev/peps/pep-0508/#names),
but that doesn't restrict the names used for import packages, only the
names used to publish and install those components. If we ever decide to
lift that restriction, it will likely be by way of
https://en.wikipedia.org/wiki/Punycode, similar to the way
internationalized domain names work, as well as the way multi-phase
extension module initialization locates init functions for extension
modules with non-ASCII names.

Beyond that, I'll note that these questions were all raised in the original
PEP: https://www.python.org/dev/peps/pep-3131/#open-issues

The reference interpreter really isn't the place to experiment with
answering them - rather, they're more a question for opt-in code analysis,
since that makes it possible for folks to choose settings that are right
*for them* (e.g. by defining a set of "permitted scripts" [1], specifying
the Unicode characters that should be allowed in identifiers beyond the
core set of "Latin" code points allowed by ASCII)

Cheers,
Nick.

[1] https://en.wikipedia.org/wiki/Script_(Unicode)

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Consider (one day) adding an inheritance order class precedence mechanism

2017-11-20 Thread Nick Coghlan
On 21 November 2017 at 12:34, Nick Coghlan <ncogh...@gmail.com> wrote:
> Right, but once you do that, then the existing resolver is already
> able to handle things:
>
> >>> class C: pass
> ...
> >>> class S(C): pass
> ...
> >>> class E: pass
> ...
> >>> class B(S, E, C): pass
> ...
> >>> class R(E, C): pass
> ...
> >>> class Z(B, R): pass
> ...
> >>>
>
> If you wanted to pick up cases where two classes generate inconsistent
> MROs that will prevent mutual subclasses (like "class B(S, E)" vs
> "class R(E, C)"), that feels like a job for a type checker, since it
> isn't obvious whether it's the definition of B or the definition of R
> that should be changed to reorder their MRO.

I do wonder if we might be able to make the error message here less
cryptic by mentioning which *listed* base classes brought in the
conflicting MRO entries.

Consider the current:

>>> class Z(B, R): pass
...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: Cannot create a consistent method resolution order
(MRO) for bases C, E

vs something like:

TypeError: Cannot create a consistent method resolution order
(MRO) for bases C, E (inherited through B, R)

(Note: I haven't actually checked how practical it would be to
implement something like that)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Consider (one day) adding an inheritance order class precedence mechanism

2017-11-20 Thread Nick Coghlan
On 21 November 2017 at 11:09, Neil Girdhar <mistersh...@gmail.com> wrote:
>
> On Sat, Nov 18, 2017 at 9:29 PM Nick Coghlan <ncogh...@gmail.com> wrote:
>>
>> >>> class C: pass
>> ...
>> >>> class S(C): pass
>> ...
>> >>> class E: pass
>> ...
>> >>> class B(S, E): pass
>> ...
>> >>> class R(E, C): pass
>> ...
>> >>> class Z(B, S, R, E, C): pass
>> ...
>> Traceback (most recent call last):
>>  File "", line 1, in 
>> TypeError: Cannot create a consistent method resolution order
>> (MRO) for bases C, E

> Sorry, I wrote back too quickly.  I meant also to change B's requested MRO
> to be:
>
> (B, S, E, C)
>
> It works with that change.

Right, but once you do that, then the existing resolver is already
able to handle things:

>>> class C: pass
...
>>> class S(C): pass
...
>>> class E: pass
...
>>> class B(S, E, C): pass
...
>>> class R(E, C): pass
...
>>> class Z(B, R): pass
...
>>>

If you wanted to pick up cases where two classes generate inconsistent
MROs that will prevent mutual subclasses (like "class B(S, E)" vs
"class R(E, C)"), that feels like a job for a type checker, since it
isn't obvious whether it's the definition of B or the definition of R
that should be changed to reorder their MRO.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Allow additional separator character in variables

2017-11-18 Thread Nick Coghlan
On 19 November 2017 at 13:22, Mikhail V <mikhail...@gmail.com> wrote:
> For me, one "cheap" solution against underscores is to use
> syntax highlighting which grays them out, but if those become like
> spaces, then it becomes a bit confusing, e.g. in function with many arguments.
> Also, unfortunately, not many editors allow easy (if any) highlighting
> customisation on that level.

Changing the way editors display underscore-using variable names still
seems like a more productive direction to explore than changing the
text encoding read by the compiler. The current source code structure
is well-defined and unambiguous, so there's no clear benefit to change
things at that level, and significant downsides in terms of
complexity, forwards and backwards compatibility concerns, and high
barriers to pervasive adoption.

By contrast, if the argument for using a different Unicode character
is "Editors will reliably display Unicode hyphen characters
differently from the way they display minus signs (or vice-versa)",
then we can just as easily say "If users are finding the way that text
editors display snake_cased_names to be consistently hard to read,
then text editors should change the way that they display
snake_cased_names (or at least make it easy for users to opt-in to
displaying them differently)".

For example, they could decide to replace underscores in variable
names for display purposes with hyphens plus the underscore combining
diacritic, or the combining macron below:

- https://en.wikipedia.org/wiki/Underline#Unicode
- https://en.wikipedia.org/wiki/Macron_below

Then when the cursor was placed inside the variable name, they could
revert to displaying those characters as regular underscores.

This kind of editor level modification would also extend itself well
to underscores in numeric literals, as there the appropriate
pseudo-separator shown when the literal wasn't being edited would be
locale dependent.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Allow additional separator character in variables

2017-11-18 Thread Nick Coghlan
On 19 November 2017 at 12:32, Nick Coghlan <ncogh...@gmail.com> wrote:
> On 19 November 2017 at 12:01, Mikhail V <mikhail...@gmail.com> wrote:
>> Python allows underscore character as a separator in variables.
>> This is better than nothing, still it does not make the look much better.
>>
>> **Proposal**: allow additional separator, namely hyphen character.
>
> Regardless of any potential readability merits, backwards
> compatibility requirements combined with the use of the hyphen
> character as a binary operator prohibit such a change:
>
> >>> my = variable = 1
> >>> my-variable
> 0

Ah, sorry - I now see you addressed the basic version of that.

The alternative of "Use a character that computers can distinguish,
but humans can't" isn't an improvement, since it means introducing the
exact kind of ambiguity that Python seeks to avoid by using
indentation for block delimeters (rather than having the computer read
braces, and humans read indentation). The difficulty of reliably
distinguishing backticks from regular single quotes is also the main
reason they're generally discounted from reintroduction for any other
use case after their usage as an alternative to the repr builtin was
dropped in Python 3.0, and it's why Python 3 prohibits mixing tabs and
spaces for indentation by default.

For anyone tempted to suggest "What about multiple underscores
indicating continuation of the variable name?", that's still a
compatibility problem due to the unary minus operator:

>>> my--variable
2
>>> my---variable
0

Would hyphens in variable names improve readability sometimes?
Potentially, but not enough to live with make binary subtraction
expressions ambiguous (hence the consistency amongst almost all
current text based programming languages on this point).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Allow additional separator character in variables

2017-11-18 Thread Nick Coghlan
On 19 November 2017 at 12:01, Mikhail V <mikhail...@gmail.com> wrote:
> Python allows underscore character as a separator in variables.
> This is better than nothing, still it does not make the look much better.
>
> **Proposal**: allow additional separator, namely hyphen character.

Regardless of any potential readability merits, backwards
compatibility requirements combined with the use of the hyphen
character as a binary operator prohibit such a change:

>>> my = variable = 1
>>> my-variable
    0

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Consider (one day) adding an inheritance order class precedence mechanism

2017-11-18 Thread Nick Coghlan
On 19 November 2017 at 06:56, Neil Girdhar <mistersh...@gmail.com> wrote:
> Would you mind explaining why it's necessary for C3 to complain?
>
> In:
>
> S < C
> B < S, E
> R < E, C
> Z < B, R
>
> If Z is told to have MRO:
>
> (Z, B, S, R, E, C)
>
> then there are no conflicts with any base classes.

I don't actually know what C3 allows in principle, I only know that
CPython's resolver still complains in practice:

>>> class C: pass
...
>>> class S(C): pass
...
>>> class E: pass
...
>>> class B(S, E): pass
...
>>> class R(E, C): pass
...
>>> class Z(B, S, R, E, C): pass
...
Traceback (most recent call last):
 File "", line 1, in 
TypeError: Cannot create a consistent method resolution order
(MRO) for bases C, E

I think the problem is that the resolver isn't looking at the declared
bases of "B", and "R", it's looking at their full MRO:

>>> B.__mro__
(, , ,
, )
>>> R.__mro__
(, , ,
)

Changing the heuristics used to generate B's MRO such that "C" and "E"
appeared in the opposite order wouldn't really help, since that would
just flip the problematic case to be the "R(C, E)" declaration.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Consider (one day) adding an inheritance order class precedence mechanism

2017-11-18 Thread Nick Coghlan
On 18 November 2017 at 09:03, Neil Girdhar <mistersh...@gmail.com> wrote:
> On Fri, Nov 17, 2017 at 3:15 AM Nick Coghlan <ncogh...@gmail.com> wrote:
>> I'll note that an interesting side effect of
>> https://www.python.org/dev/peps/pep-0560/#mro-entries will be to allow
>> folks to write:
>>
>> class MyCustomMRO:
>> def __init__(self, *bases):
>> self._resolved_bases = my_mro_resolver(bases)
>> def __mro_entries(self, orig_bases):
>> if len(orig_bases) > 1 or orig_bases[0] is not self:
>> raise TypeError("CustomMRO instance must be sole base
>> class")
>> return self._resolved_bases
>>
>>
>> class Z(MyCustomMRO(B, R)):
>> ...
>>
>> The custom MRO algorithm may then allow for use case specific hints to
>> handle situations that the default C3 resolver will reject as
>> inconsistent or ambiguous. (I'll also note that such a custom resolver
>> would be able to manufacture and inject synthetic metaclasses if
>> that's what someone decided they really wanted to do, by also
>> synthesising a custom base class to stick at the head of the list of
>> bases).
>
> This is really cool!

Unfortunately, as Koos noted, it doesn't actually work as simply as I
presented it: even if you spell out a full MRO in the most-derived
class, the C3 resolution algorithm will complain that it's
inconsistent with the order in one of the two conflicting base
classes.

So to truly get a custom method resolution order, you're likely going
to end up needing a custom metaclass involved.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Consider (one day) adding an inheritance order class precedence mechanism

2017-11-17 Thread Nick Coghlan
On 17 November 2017 at 15:52, Steven D'Aprano <st...@pearwood.info> wrote:
> There's a lot of benefit to having a relatively simple, understandable
> algorithm for determining the MRO, as opposed to some sort of adaptive
> rule that will try to reorder classes according to potentially clashing
> constraints. If that means that some classes cannot go together in
> multiple inheritence because their MRO would be inconsistent, I think
> that's a price worth paying for not having to debug inheritence bugs
> caused by weirdly reordered MROs.

I'll note that an interesting side effect of
https://www.python.org/dev/peps/pep-0560/#mro-entries will be to allow
folks to write:

class MyCustomMRO:
def __init__(self, *bases):
self._resolved_bases = my_mro_resolver(bases)
def __mro_entries(self, orig_bases):
if len(orig_bases) > 1 or orig_bases[0] is not self:
raise TypeError("CustomMRO instance must be sole base class")
return self._resolved_bases


class Z(MyCustomMRO(B, R)):
...

The custom MRO algorithm may then allow for use case specific hints to
handle situations that the default C3 resolver will reject as
inconsistent or ambiguous. (I'll also note that such a custom resolver
would be able to manufacture and inject synthetic metaclasses if
that's what someone decided they really wanted to do, by also
synthesising a custom base class to stick at the head of the list of
bases).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-16 Thread Nick Coghlan
On 17 November 2017 at 05:15, Chris Barker <chris.bar...@noaa.gov> wrote:

> On Wed, Nov 15, 2017 at 11:07 AM, Steve Dower <steve.do...@python.org>
> wrote:
>
>> If you write such a PEP, please also research and write up the issues
>> with modifying PATH on Windows (they're largely scattered throughout
>> bugs.p.o and earlier discussions on python-dev).
>>
>
> Is anyone proposing doing anything new with that? (other than changing the
> default)
>
> My preferred solution for this is to rename "py.exe" to "python.exe"
>
>
> I was going to propose that in this thread, but then thought: "there has
> GOT to be a reason why that reall obvious solution wan't done in the first
> place", and didn't have time to go back and research it.
>

As far as I recall, the arguments against it are:

- wanting the regular executable and the launcher to be able to coexist in
the same build target directory
- not wanting the regular python executable to prevent access to the
launcher at a shell prompt
- not wanting the launcher at a shell prompt to prevent access to the
regular executable at a shell prompt

However, https://www.python.org/dev/peps/pep-0397/ doesn't spell those out,
it just states what the launcher's name will be, and emphasises that the
main purpose is to provide a sensible target for file associations after
the "always use the most recently installed version" assumption broke down:
https://www.python.org/dev/peps/pep-0397/#rationale

Addressing them now:

* as long as the extra hard links are only generated at install time, there
also won't be any problems with build directory name conflicts.
* the launcher will always be available a `py`, regardless of the current
PATH
* PATH in a venv will still put the regular python executable ahead of the
launcher

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-15 Thread Nick Coghlan
On 16 November 2017 at 05:29, Zachary Ware <zachary.ware+py...@gmail.com>
wrote:

> On Wed, Nov 15, 2017 at 1:07 PM, Steve Dower <steve.do...@python.org>
> wrote:
> > My preferred solution for this is to rename "py.exe" to "python.exe" (or
> > rather, make a copy of it with the new name), and extend (or more likely,
> > rewrite) the launcher such that:
> >
> > * if argv[0] == "py.exe", use PEP 514 company/tag resolution to find and
> > launch Python based on first command line argument
> > * if argv[0] == "python.exe", find the matching
> > PythonCore/ install (where tag may be a partial match - e.g.
> > "python3.exe" finds the latest PythonCore/3.x)
> > * else, if argv[0] == ".exe, find the matching
> > PythonCore/ install and launch "-m "
> >
> > With the launcher behaving like this, we can make as many hard links as
> we
> > want in its install directory (it only gets installed once, so only needs
> > one PATH entry, and this is C:\Windows for admin installs):
> > * python.exe
> > * python2.exe
> > * python3.exe
> > * python3.6.exe
> > * pip.exe
> > * pip2.exe
> > * pip3.exe
>
> I haven't been following this thread closely, but this sounds lovely.
> I'm not terribly keen on cluttering up C:\Windows with this, but
> that's a minor issue.
>

I'd missed Steve's post before writing my last one. This sounds like a
really nice technical solution to me, too, especially as it will handle
Python 2 as well (even for Python 2 only systems, the launcher is available
as an independently installable executable).

Regardless of the underlying implementation details though, a PEP would be
a helpful way of writing it up so we can make sure packaging.python.org and
other resources properly account for it.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-15 Thread Nick Coghlan
On 15 November 2017 at 22:46, Michel Desmoulin <desmoulinmic...@gmail.com>
wrote:

> Le 13/11/2017 à 19:57, Chris Barker a écrit :
> > 3) Make --user be be automatic for pip install. Not actually the
> > default, but pip could do a user install if you don't have the
> > permissions for a non-user install.
>
> Breaking compat ? Not sure people will accept.
>

This isn't actually a Python level change - it's a pip UX level one, and
already on their todo list: https://github.com/pypa/pip/issues/1668

I believe the next concrete step that can be taken there is to actually add
an explicit `--global` flag, so I've belatedly broken that out as its own
issue: https://github.com/pypa/pip/issues/4865

=
>
> Should I do a PEP with a summary of all the stuff we discussed ?
>

I think a Windows-specific PEP covering adding PATH updates back to the
default installer behaviour, and adding pythonX and pythonX.Y commands
would be useful (and Guido would presumably delegate resolving that to
Steve Dower as the Windows installer maintainer).

The one thing I'd ask is that any such PEP *not* advocate for promoting
ther variants as the preferred way of invoking Python on Windows - rather,
they should be positioned as a way of making online instructions written
for Linux more likely to "just work" for folks on Windows (similar to the
utf-8 encoding changes in https://www.python.org/dev/peps/pep-0529/)

Instead, the focus should be on ensuring the "python -m pip install" and
"pip install" both work after clicking through the installer without
changing any settings, and devising a troubleshooting guide to help folks
that are familiar with computers and Python, but perhaps not with Windows,
guide folks to a properly working environment.

The update to the Windows installer would then start offering benefits as
soon as Python 3.7 becomes the default download, while the troubleshooting
guide would be beneficial as soon as folks start learning about it's
existence.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-15 Thread Nick Coghlan
On 15 November 2017 at 19:51, Paul Moore <p.f.mo...@gmail.com> wrote:

> On 15 November 2017 at 08:22, Nick Coghlan <ncogh...@gmail.com> wrote:
> > On 15 November 2017 at 16:13, Steve Barnes <gadgetst...@live.co.uk>
> wrote:
> >>
> >>   - "pip -X[.Y][-32|-64] operation ..." tries to find a python matching
> >> -X[.Y][-32|-64] and if it succeeds executes "python -m pip operation
> >> ..." with that python, (if it doesn't find a matching python is should
> >> fail with a sensible error message and possibly list the valid python
> >> specifiers).
> >
> >
> > This is a genuinely interesting option, especially as `pipenv` has
> already
> > implemented a feature somewhat akin to this:
> > https://docs.pipenv.org/basics.html#specifying-versions-of-python
> >
> > `pipenv` also allows `pipenv --two` and `pipenv --three` when setting up
> > your initial virtual environment.
>
> This is an interesting idea for *any* tool that's about "working with
> Python environments" as opposed to "writing Python code". So pip,
> virtualenv, tox, pipenv, ... Many of these tools are variously
> reinventing "tell me which Python environment to work on" options.
> Having a common way to do this would be really useful. I'm not sure
> how likely it would be for pip to be able to use it (pip introspects
> sys.executable to get site-packages, etc), but it's certainly a
> possibility.
>
> Having a standardised library/wrapper that handles the "select a
> Python environment" process would be a huge plus. There's
> https://github.com/zooba/pep514tools which is a start on handling the
> Windows registry scanning logic, and building on that to include Unix
> and anything else we needed would be great.
>

While I suspect pep514tools itself may not end up being the right place, I
filed https://github.com/zooba/pep514tools/issues/2 to start discussing
that idea further. For other platforms, just naively scanning `PATH` is
often good enough, so it's mainly Windows where discovery needs to be a bit
more aware of platform specific details (i.e. PEP 514's registry entries).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] A proliferation of (un-)Pythonically programmatic pragmas

2017-11-15 Thread Nick Coghlan
On 14 November 2017 at 10:27, Brett Cannon <br...@python.org> wrote:

>
> On Mon, Nov 13, 2017, 15:55 Steven D'Aprano, <st...@pearwood.info> wrote:
>
>> On Mon, Nov 13, 2017 at 06:37:05PM -0500, Barry Warsaw wrote:
>> > Brett Cannon wrote:
>> >
>> > > And possibly the easiest way to reach them is on the pyqa-dev mailing
>> list.
>> >
>> > What's that?  I can't find it on python.org, Gmane, or the Googles.
>>
>> Brett may have meant
>>
>> https://mail.python.org/mailman/listinfo/code-quality
>
>
> Steve's right. http://meta.pycqa.org/en/latest/
>

I think that will be the right way to go about it, as this seems similar to
a lot of the problems that arise in the packaging interoperability space:
what really matters is what tool developers support in practice, so
documenting a proposed convention without a clear implementation plan
across common tools wouldn't really achieve a great deal.

This means that any new convention ideas need to be discussed and supported
by the tool developers, with python-dev & python-ideas really only getting
involved if some standard library adjustments are needed (e.g. updating
doctest to abide by any proposed conventions), or if the convention is
going to be captured as an informational PEP, rather than solely as a
recommended comment parsing library.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-15 Thread Nick Coghlan
On 15 November 2017 at 16:13, Steve Barnes <gadgetst...@live.co.uk> wrote:

>   - "pip -X[.Y][-32|-64] operation ..." tries to find a python matching
> -X[.Y][-32|-64] and if it succeeds executes "python -m pip operation
> ..." with that python, (if it doesn't find a matching python is should
> fail with a sensible error message and possibly list the valid python
> specifiers).
>

This is a genuinely interesting option, especially as `pipenv` has already
implemented a feature somewhat akin to this:
https://docs.pipenv.org/basics.html#specifying-versions-of-python

`pipenv` also allows `pipenv --two` and `pipenv --three` when setting up
your initial virtual environment.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-14 Thread Nick Coghlan
On 15 November 2017 at 01:23, Stephan Houben <stephan...@gmail.com> wrote:

> Hi Nick,
>
> 2017-11-14 11:07 GMT+01:00 Nick Coghlan <ncogh...@gmail.com>:
>
>> On 14 November 2017 at 16:47, Michel Desmoulin <desmoulinmic...@gmail.com
>> > wrote:
>>
>>> Proposal A:
>>> ---
>>>
>>> Suffix Python executable on Windows like on Unix, so that people will
>>> type pythonX.X if they want a specify version.
>>>
>>> Pros: easy and discoverable.
>>>
>>> Cons: you need a lot of stuff in the system path.
>>>
>>
>> Con: we hope to have the problem resolved on the Linux distro side such
>> that "python" typically means "python" by the time community support for
>> Python 2 ends in 2020. Since Windows has gone the better part of two
>> decades without version Python commands, adding them because we're
>> impatient with the pace of change at the Linux distro level doesn't really
>> make sense (especially when Linux holds such a small fraction of the
>> non-phone client device market).
>>
>
> Perhaps I could sell you on the idea of a Windows "python3" executable,
> not as the New Official Way to do things,
> but rather as a pragmatic measure to make code from those Linux weirdos
> ;-)
>

Aye, I'm not opposed to adding pythonX and pythonX.Y binaries or symlinks
to the Windows installers as a way to make Linux-assuming tutorials
slightly more likely to work for Windows users.

I'm only opposed to promoting that as the new preferred way of launching
Python from the Windows command line, if for no other reason than if the
release after Python 3.9 actually does end up being Python 4.0, then we
only have around 5 more years of "the latest Python" and "the latest Python
3.x" being the same thing :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Modules as global namespaces rather than dicts

2017-11-14 Thread Nick Coghlan
On 15 November 2017 at 06:34, Neil Schemenauer <nas-python-id...@arctrix.com
> wrote:

> So, what is the purpose of all this trouble?
>
> - I believe quite a lot of Python internals can be simpler.  For
>   example, importlib is complicated by the fact that a dict is
>   passed around when most of the logic would prefer to have the
>   module.  Grubbing in sys.modules to lookup the module object is
>   ugly.  The expression "exec(code, module)" is elegant to me.
>

I like the idea in principle, but highlighting a particular backwards
compatibility pain point: one of the complications in importlib is that we
promise to keep the "sys.modules[__name__] = some_other_object" idiom
working. That means the need to do that check exists regardless of whether
importlib is passing the module itself around, or the module's dict.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-14 Thread Nick Coghlan
pip and venv part of the standard and request debian that they
> provide it.
>
> Pros: straight forward.
>
> Cons: holy war in the making.
>

I don't think it's *that* bad. Debian does have support for weak
dependencies, so the resolution here may be as simple as asking Matthias to
add a Recommends from python3 to python3-venv so that ensurepip is present
by default on typical workstation configurations, but can still be easily
omitted from server configurations.



> Favorite personnal combination
> 
>
> 1 - So far, I like "providing py on unix" better, but I think it's too
> hard to do. So provide suffix on windows seems more achievable.
>
> So +1 for having pythonX.X on windows.
>

I think this is actually similar to the situation with 'py' on *nix
systems: with Windows having never had these before, adding and promoting
them would be at best ineffective, and at worst outright confusing
(especially if "python" starts meaning Python 3 by default on Linux as well
within the next few years).


> 2 - Decide on one form, and promote it everywhere is again the simplest
> IMO. I love pipenv but the strings to pull to get something like this
> means it probably would not happen.
>

We've been evaluating a potential pipenv tutorial for the Python Packaging
User Guide, and while we're likely going to add it soon, it will be as a
new "application dependency management" tutorial alongside the existing
ones, rather than as a direct replacement for the pip-based "package
installation" tutorial:
https://github.com/pypa/python-packaging-user-guide/issues/394#issuecomment-343343760


> If we stick to suffix for issue 1, this mean we can promote:
>
> pythonX.X -m pip
> pythonX.X -m venv
>
> Everywhere. In the docs. In the tutorials. In teaching classes.
>
> This will help a lot to remove all confusions and make the Python start
> up experience way easier.
>

Except it won't, because now you can't seamlessly update your class
instructions to new versions of Python - you'll have to go through and
change all the "X.Y" references to refer to the right version. Writing
cross-platform scripts will also get even harder, as you wouldn't be able
to say "I just need a version of Python, I don't really care which one" any
more.

Python feature releases are already disruptive enough due to filesystem
layout changes and file format changes - we don't need to make them worse
by encouraging people to embed the exact target version in their
documentation and helper scripts.


> 3 - getting angry debian devs is probably not wise. The "mock" pip/venv
> command also plays very well with the 2 other solutions.
>

While I was a bit snarky about "python -m venv" being broken by default
earlier in the thread, *please* don't take that as meaning that we can't
collaborate constructively with the Debian folks. We can, and do, but the
friction between language level package management and system level package
management is one with a *long* history that we're all working towards
resolving together (See [1] & [2] for write-ups of a couple of linux.conf.au
talks I've given about the problem), as is the question of how best to
handle the `/usr/bin/python` symlink.


> It means we can promote everywhere:
>
> pythonX.X -m cmd
>
> It will work most of the time.


The combination of:

pip install package
python -m venv

already works in most cases, *except* apparently the critical one of "New
Python user on Windows downloads the python.org installer and clicks
through all the buttons without changing any settings".

So I think the main near term step forward would be to convince Steve Dower
(as the Windows installer maintainer) to change that default behaviour yet
again for 3.7, and then work towards coming up with a solid environment
troubleshooting guide to include on packaging.python.org.

Cheers,
Nick.

[1] https://lwn.net/Articles/580399/
[2] https://lwn.net/Articles/711906/

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-13 Thread Nick Coghlan
On 14 November 2017 at 13:08, Nathaniel Smith <n...@pobox.com> wrote:

> On Nov 13, 2017 6:47 PM, "Nick Coghlan" <ncogh...@gmail.com> wrote:
>
> On 14 November 2017 at 11:51, Nathaniel Smith <n...@pobox.com> wrote:
> > What if instead of installing a standard entry point, the pip
> > executable was installed as
> >
> > #!/bin/sh
> > exec python -m pip "$@"
> >
> > on Unix-likes
>
> It would technically be enough to make the shebang line
> `#!/usr/bin/env python` so the interpreter used was picked up from the
> environment, rather than being preconfigured at install time. However,
> the problem is that you don't know for certain that that python will
> actually have `pip` installed, so it might just fail with a cryptic
> error instead.
>
>
> This would still be a massive improvement over the status quo, which in
> this situation would present a perfect simulacrum of downloading and
> installing the package you asked for, except then when you start python the
> import still fails.
>
> I did think of another issue: when installing into a virtualenv, we
> probably want to keep the current system, so explicit/path/bin/pip
> continues to work as expected.
>

My essential concern is that I don't think we should be opening ourselves
up to *even more* platform dependent behaviours in this area.

Instead, if we decide that we would like to request that pip to start doing
something different when:

* `sys.executable` and `shutil.which('python')` are inconsistent with each
other
* `sys.argv[0]` doesn't end with `site-packages/pip/__main__.py` and isn't
`shutil.which('pip')`

then we'd be better off putting that logic in pip's Python code, rather
than in the platform dependent script wrappers where we can't control the
error messages presented when our expectations aren't met.

I do like the idea of making that distinction in principle though, as it's
a better one than "inside a virtual environment or not?".

While Python level venvs are *a* way to obtain the desired pip/python
consistency, they're not the only one:

- Arch Linux does it by default
- Docker's Python 3 images do it by default (Alpine Linux may even do it by
default in general)
- Windows installs do it by default (if PATH is configured correctly)
- conda env does it
- Software Collections do it (including in the Python 3 Docker images for
RHEL & CentOS)
- *nix environment modules do it
- system admins may set up per-user install profiles to do it
- etc...

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 560 (second post)

2017-11-13 Thread Nick Coghlan
On 14 November 2017 at 09:41, Guido van Rossum <gu...@python.org> wrote:
> On Fri, Nov 10, 2017 at 8:54 AM, Ivan Levkivskyi <levkivs...@gmail.com>
> wrote:
>>
>> On 10 November 2017 at 17:43, Guido van Rossum <gu...@python.org> wrote:
>>>
>>> There seem to be some action items from this thread that I haven't seen
>>> reflected in the PEP source code yet.
>>> [...snip...]
>>> Then the next step I propose is a PR with a full implementation. After
>>> that I'll likely approve the PEP (or we'll have minor feedback based on
>>> trying the implementation).
>>
>>
>> Yes, sorry, I wanted to make updates to the PEP and reference
>> implementation,
>> but last two weeks were very busy.
>> Hopefully, I will work on it this weekend.
>
> Thanks, I am happy now with the PEP, except for one detail: maybe
> `__mro_entry__` should always return a tuple and then maybe renamed to
> `__mro_entries__`. (See debate at
> https://github.com/python/peps/pull/460#issuecomment-343969528 .)

I like that - very nice refinement.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-13 Thread Nick Coghlan
On 14 November 2017 at 11:51, Nathaniel Smith <n...@pobox.com> wrote:
> What if instead of installing a standard entry point, the pip
> executable was installed as
>
> #!/bin/sh
> exec python -m pip "$@"
>
> on Unix-likes

It would technically be enough to make the shebang line
`#!/usr/bin/env python` so the interpreter used was picked up from the
environment, rather than being preconfigured at install time. However,
the problem is that you don't know for certain that that python will
actually have `pip` installed, so it might just fail with a cryptic
error instead.

However, `pip` could potentially be updated with a `checkenv`
subcommand that complains if `sys.executable` and
`shutil.which('python')` don't match (and could presumably include
other checks as well).

> and a pip.bat with the equivalent contents on Windows?
> (Bonus: maybe this would fix the problem with upgrading pip on
> Windows?)

Depending on how the batch file was written, I think the answer to
that is "maybe":
https://stackoverflow.com/questions/2888976/how-to-make-bat-file-delete-it-self-after-completion/20333152#20333152

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] venv *is* provided in the standard Python install on Debian/Ubuntu

2017-11-13 Thread Nick Coghlan
On 13 November 2017 at 20:43, Antoine Pitrou <solip...@pitrou.net> wrote:
> On Mon, 13 Nov 2017 11:17:54 +0100
> Petr Viktorin <encu...@gmail.com> wrote:
>> >
>> > Wow.  I had forgotten Debian could be such a user-hostile
>> > distribution.  I'm not sure what the reason would be to use it as a
>> > basis for a training course in Python programming, then (other than the
>> > teacher having their own ideological preferences).
>>
>> For us, it's the *student's* preference. I believe it's better to let
>> students use the machine and environment they're used to, even if it
>> means extra trouble for the instructors.
>> So, we get a healthy mix of Windows, Mac, Debian, Fedora, and sometimes
>> some surprises.
>
> In that case the student must be ready to deal with the perils of their
> own preferences.

It's also currently missing from
https://packaging.python.org/guides/installing-using-linux-tools/, but
we can amend that now that we know what the required fix is.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] venv *is* provided in the standard Python install on Debian/Ubuntu

2017-11-13 Thread Nick Coghlan
On 13 November 2017 at 17:46, Stephan Houben <stephan...@gmail.com> wrote:
> 2017-11-13 3:32 GMT+01:00 Nick Coghlan <ncogh...@gmail.com>:
>> So technically it's ensurepip that's broken by default, but that
>> translates to venv also being broken by default.
>>
>> I haven't worked out what the actual steps needed to fix it are
>
> On Debian, ensurepip  is in the python3.5-venv package.
>
> https://packages.debian.org/stretch/amd64/python3.5-venv/filelist

Thanks! I've tweaked the ncoghlan/debian-python Dockerfile to install
that in addition to the base Python package (as well as finally
enabling automatic rebuilds of that image whenever the base Debian
image updates).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] venv *is* provided in the standard Python install on Debian/Ubuntu

2017-11-12 Thread Nick Coghlan
On 13 November 2017 at 04:38, Antoine Pitrou <solip...@pitrou.net> wrote:
> On Sun, 12 Nov 2017 12:20:45 +
> Paul Moore <p.f.mo...@gmail.com> wrote:
>>
>> > Well, not exactly. Do you do python -m venv, or py -x.x -m venv or
>> > pythonx -m venv ? Wait, it's not installed by default on debian.
>>
>> Seriously? Debian don't provide venv in the standard Python install?
>> That's just broken.
>
> Frankly, I don't know where the current discussion comes from, but on
> two recent Debian and Ubuntu setups, I get:
>
> $ dpkg -S /usr/lib/python3.5/venv/__init__.py
> libpython3.5-stdlib:amd64: /usr/lib/python3.5/venv/__init__.py

The discussion comes from the fact that even though the code is
present it doesn't actually work:

$ docker run --rm -it ncoghlan/debian-python bash
root@e9c0aa482aeb:/# python3 -m venv test_venv
Error: Command '['/test_venv/bin/python3', '-Im', 'ensurepip',
'--upgrade', '--default-pip']' returned non-zero exit status 1

(I just refreshed my Docker image to 9.2, so that's the current
default behaviour after "apt-get install -y python3")

So technically it's ensurepip that's broken by default, but that
translates to venv also being broken by default.

I haven't worked out what the actual steps needed to fix it are (but I
do know that installing "python3-pip" isn't enough the way it is on
Fedora - we reconcile ensurepip with our security management policies
by having a Recommends dep from python3 to python3-pip, and then
patching ensurepip to use rewheel to inject a copy of the system pip
into freshly created virtual environments. At least in theory, Debian
should be able to do something similar with dirtbike, but whether or
not they actually will would be a question for Matthias Klose as the
Debian Python maintainer).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] venv *is* provided in the standard Python install on Debian/Ubuntu

2017-11-12 Thread Nick Coghlan
On 13 November 2017 at 09:29, Nick Coghlan <ncogh...@gmail.com> wrote:
> On 13 November 2017 at 07:11, Chris Angelico <ros...@gmail.com> wrote:
>> On Mon, Nov 13, 2017 at 6:24 AM, Stephan Houben <stephan...@gmail.com> wrote:
>>> Hi Antoine,
>>>
>>> The venv module is included,
>>> however the pyvenv script is in a separate package
>>> python3.5-venv .
>>>
>>> By the way, I was totally confused by the following text form the doc.
>>>
>>> https://docs.python.org/3/library/venv.html
>>>
>>> 
>>> Deprecated since version 3.6: pyvenv was the recommended tool for creating
>>> virtual environments for Python 3.3 and 3.4, and is deprecated in Python
>>> 3.6.
>>>
>>> Changed in version 3.5: The use of venv is now recommended for creating
>>> virtual environments.
>>>
>>> 
>>
>> Not sure where you're reading that. I'm seeing:
>>
>> """
>> Note
>> The pyvenv script has been deprecated as of Python 3.6 in favor of
>> using python3 -m venv to help prevent any potential confusion as to
>> which Python interpreter a virtual environment will be based on.
>> """
>>
>> I think that's pretty clear. "python3 -m venv env" is the standard and
>> recommended way to spin up a virtual environment.
>
> It's further down in the page, under
> https://docs.python.org/3/library/venv.html#creating-virtual-environments
>
> I think the deprecation notice for pyvenv should just be deleted,
> since it renders like the *module* is deprecated.

That is, the confusing one starting with "Deprecated since version
3.6: ...". The note Chris quoted is fine, and should be kept.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] venv *is* provided in the standard Python install on Debian/Ubuntu

2017-11-12 Thread Nick Coghlan
On 13 November 2017 at 07:11, Chris Angelico <ros...@gmail.com> wrote:
> On Mon, Nov 13, 2017 at 6:24 AM, Stephan Houben <stephan...@gmail.com> wrote:
>> Hi Antoine,
>>
>> The venv module is included,
>> however the pyvenv script is in a separate package
>> python3.5-venv .
>>
>> By the way, I was totally confused by the following text form the doc.
>>
>> https://docs.python.org/3/library/venv.html
>>
>> 
>> Deprecated since version 3.6: pyvenv was the recommended tool for creating
>> virtual environments for Python 3.3 and 3.4, and is deprecated in Python
>> 3.6.
>>
>> Changed in version 3.5: The use of venv is now recommended for creating
>> virtual environments.
>>
>> 
>
> Not sure where you're reading that. I'm seeing:
>
> """
> Note
> The pyvenv script has been deprecated as of Python 3.6 in favor of
> using python3 -m venv to help prevent any potential confusion as to
> which Python interpreter a virtual environment will be based on.
> """
>
> I think that's pretty clear. "python3 -m venv env" is the standard and
> recommended way to spin up a virtual environment.

It's further down in the page, under
https://docs.python.org/3/library/venv.html#creating-virtual-environments

I think the deprecation notice for pyvenv should just be deleted,
since it renders like the *module* is deprecated.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-12 Thread Nick Coghlan
On 13 November 2017 at 02:59, Brendan Barnwell <brenb...@brenbarn.net> wrote:
> On 2017-11-12 05:18, Nick Coghlan wrote:
>>
>> * the `pip install` option really is nicer looking than `python -m pip
>> install`, and it only has actual problems in the presence of multiple
>> Python versions and when upgrading pip itself on Windows (plus: lots
>> of third party guides recommend it, as do pypi.org project pages)
>
>
> Is there any *advantage* to using `pip install` instead of `python
> -m install`?  If not, could we at least change everything under Python/pip
> control (e.g., pip documentation) to never recommend `pip` and always
> recommend `python -m pip` instead, and encourage all third-party
> documentation to always use `python -m pip` and never use `pip`?

We've already changed most of them (pypi.org itself is the main one
that we haven't changed it yet).

However, there are still per-project READMEs out there that suggest
"easy_install project" and direct invocation of "python setup.py
install", so it really isn't appealing to layer yet another mandatory
change in the recommended spelling of the installation command and
create yet another point of confusion - it will be much nicer overall
if we can retroactively make the existing "pip install" instructions
correct for most users, and leave "python -m pip install" to the
"Multiple versions of Python" and "Self-upgrading pip on Windows".

Cheers,
Nick.

P.S. As a user, it's also genuinely irritating to have to always type
the "python -m " prefix when inside an active virtual environment, as
in that case, there isn't any ambiguity about which environment pip
should be manipulating or which version of Python it should be using.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-12 Thread Nick Coghlan
rties", like those Django Girls runs (i.e. running a
pre-tutorial event, specifically focused on getting a working
environment set up)
* highly prescriptive learning environments, whether online ones (like
Grok Learning, trinket.io, PythonAnywhere, etc), or locally installed
ones (like PyCharm Educational Edition, the Anaconda distribution,
etc)

Without the kinds of constraints suggested in the last option, there
are too many potential starting points, and it isn't even possible to
ask potential learners to self-assess what their starting point
actually is, since it's a tech support problem where the first task is
"assess the current state of the user's system" (hence the first two
options).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-12 Thread Nick Coghlan
On 12 November 2017 at 16:20, Michel Desmoulin
<desmoulinmic...@gmail.com> wrote:
> Le 10/11/2017 à 09:01, Nick Coghlan a écrit :
>> On 10 November 2017 at 17:05, Michel Desmoulin
>> <desmoulinmic...@gmail.com> wrote:
>> When we choose not to use venv, then it becomes necessary to ensure
>> each of those things individually for each potential system starting
>> state
>>
> The way we do things is not the only way. Take JS: they don't have this
> problem, you npm install the same way everywhere. You don't have
> virtualenv but local node_modules. And you have transpilers to help with
> the langage version differences.

And they have browser manufacturers pouring millions of dollars a year
into their tooling ecosystem into order to influence whose ad networks
get clicked on most often.

Python doesn't have that level of investment, but we do have fine
folks volunteering to work on projects like `pip`, `virtualenv`, PyPI,
and the packaging.python.org documentation project, as well as
backports of standard library modules to earlier Python versions.

When someone attempts to explain to you the practical challenges that
limit both python-dev's and PyPA's ability to reliably control the
starting experience of new Python users, the appropriate response is
to *start listening*, not harangue them for failing to immediately
follow your peremptory orders to make things simpler for you.

"Do it because I said so" is bad management style even in an actual
company - it's even worse in a peer production environment like an
open source community.

> Now I'm not advocating we do it the JS way. I'm just saying that you are
> very keen to defend a statu quo instead of offering ideas to solve the
> problem.

I already opened
https://github.com/pypa/python-packaging-user-guide/issues/396 to
track possible areas of concrete near term improvement (I would have
tagged you on the issue, but I couldn't find a GitHub account under
your name).

> Besides, using venv have the same issues. It's not installed on linux by
> defaut.

That depends greatly on which Linux you install - the choice on
whether to deliberately cripple "python3 -m venv" or not is made by
the maintainers for that distribution, and Python-friendly distros
make sure Python's native tooling works properly by default.

> And on windows you'll have to do py -x.x -m but on mac pythonx -m.

CPython updates take years to reliably roll out to end user systems,
so if you're looking to have an impact in a shorter time frame than
that, the differences in cross-platform invocation are a constraint
you're going to have to learn to live with.

Regards,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-10 Thread Nick Coghlan
On 10 November 2017 at 19:50, Paul Moore <p.f.mo...@gmail.com> wrote:
> On 10 November 2017 at 08:01, Nick Coghlan <ncogh...@gmail.com> wrote:
>> That tooling is venv:
>>
>> * it ensures you have "pip" on your PATH
>> * it ensures you have "python" on your PATH
>> * it ensures that you have the required permissions to install new packages
>> * it ensures that any commands you install from PyPI will be also on your 
>> PATH
>>
>> When we choose not to use venv, then it becomes necessary to ensure
>> each of those things individually for each potential system starting
>> state
>
> Currently, the reality is that people use virtualenv, not venv. All
> higher-level tools I'm aware of wrap virtualenv (to allow Python 2.7
> support). Enhancing the capabilities of venv is fine, but promoting
> venv over virtualenv involves technical challenges across the whole
> toolset, not just documentation/education.

We already assume there will be a step in understanding from "working
with the latest Python 3.x locally" to "dealing with multiple Python
versions". Switching from venv to virtualenv just becomes part of that
process (and will often be hidden behind a higher level tool like
pipenv, pew, or vex anyway).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-10 Thread Nick Coghlan
On 10 November 2017 at 17:05, Michel Desmoulin
<desmoulinmic...@gmail.com> wrote:
>
>> Which is why we advise getting into a virtual environment ASAP, such
>> that the only platform specific thing folks necessarily need to learn
>> to get started is how to get to that first working virtual
>> environment.
>>
>
> You can't start by teaching virtualenv. I tried. It doesn't work. And
> it's a terrible prerequisit if you write docs, tutorial, teaching
> materials, etc.

You can't have it both ways - the only way we can systematically mask
the environmental differences between Windows, Linux and Mac OS X is
by providing tooling that actually masks those differences, which
means introducing that tooling becomes a prerequisite for teaching.

It doesn't completely solve the problem (as getting into and out of
the environment is still platform specific), but it does mean that the
ubiquitous online instructions to run "pip install package-name" and
"python -m command" will actually work once people are inside their
working environment.

That tooling is venv:

* it ensures you have "pip" on your PATH
* it ensures you have "python" on your PATH
* it ensures that you have the required permissions to install new packages
* it ensures that any commands you install from PyPI will be also on your PATH

When we choose not to use venv, then it becomes necessary to ensure
each of those things individually for each potential system starting
state

That said, we'd *like* the default to be is per-user package
installations into the user home directory, but that creates
additional problems:

* "python" may be missing, and you'll have to use "python3" or "py" instead
* "pip" may be missing (or mean "install for Python 2.7")
* you have to specify "--user" on *every* call to pip, and most online
guides won't say that
* there's a major backwards compatibility problem with switching pip
over to per-user package installs as the default (we still want to do
it eventually, though)
* on Windows, system-wide Python installs can't adjust per-user PATH
settings, and per-user installs are subject to being broken by
system-wide installs
* on Windows, the distinction between a per-user install of Python,
and per-user installs of a package is hard to teach
* on Debian, I believe ~/.local/bin still isn't on PATH by default

That said, I think there is one improvement we could feasibly make,
which would be to introduce the notion of a "default user environment"
into `venv`, such that there was a single "python -m venv shell"
command that:

* created a default user environment if it didn't already exist
* launched a subshell with that environment already activated

This wouldn't be a full environment manager like vex or pew - it would
just be a way to bootstrap a single usable package management
environment in a cross-platform way.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-09 Thread Nick Coghlan
On 10 November 2017 at 16:55, Michel Desmoulin
<desmoulinmic...@gmail.com> wrote:
> ensurepip may depend of youself having an internet connection when you
> install it. And without a proxy. And it's not used on debian flavours.

No, ensurepip doesn't depend on internet access (by design - it's the
main reason why CPython bundles the wheel files).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Proposal to change Python version release cycle

2017-11-07 Thread Nick Coghlan
On 6 November 2017 at 22:19, Stephan Houben <stephan...@gmail.com> wrote:
> 2017-11-06 12:53 GMT+01:00 Brice Parent <cont...@brice.xyz>:
>> I think the only problem we can reach here, not only in our lifetimes, but
>> in the next years, is not Python3.10 vs Python31.0 (Python3.x will be long
>> dead when we reach this point!), but the ordering of versions, like
>> (python310 < python40). But it probably is a false problem, as after a
>> two-digit minor version, we can fix the length of minor versions to two
>> digits when needed (python310 < python400).
>
> No probs with either of my proposals:
>
>>>> "python39.dll" < "python3A.dll" < "python40.dll"
> True

Ah, you're right, I forgot about that option (I think Ezio Melotti
suggested it previously).

Yes, going with "3.10", but encoding it as "3A" in lexically ambiguous
contexts is another option that would let us get as far as 3.35 (aka
"3Z") before encountering ambiguity problems.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-07 Thread Nick Coghlan
On 7 November 2017 at 03:52, Michel Desmoulin <desmoulinmic...@gmail.com> wrote:
>
>
> Le 06/11/2017 à 09:47, Nick Coghlan a écrit :
>> On 6 November 2017 at 16:47, Michel Desmoulin <desmoulinmic...@gmail.com> 
>> wrote:
>>> I really want some people from this list to discuss here so we can find
>>> a way to either unify a bit the way we install and use pip, or find a
>>> way to express a tutorial that always works for people on the most
>>> popular platforms and spread the word so that any doc uses it.
>>
>> https://docs.python.org/3/installing/#basic-usage is as close as we've
>> been able to get to that for the time being.
>
> I know and you still:
>
> - have to use py -m on windows, python3 linux, python in virtualenv...

Which is why we advise getting into a virtual environment ASAP, such
that the only platform specific thing folks necessarily need to learn
to get started is how to get to that first working virtual
environment.

> - install pip manually on linux

s/Linux/Ubuntu/

Other distros (like Fedora) provide pip by default.

> - make sure the system path is correctly set

Recent python.org Windows installers do this automatically, but there
are unfortunately still lots of ways for things to go wrong.

> Stuff that they will forget on the next install, or miss when changing
> plateform.

Yes, because computers are awful, and incredibly user hostile. We
don't have a magic wand to wave to fix that.

> And assume that stuff in any tutorial you make they know this stuff.
>
> This is a strong barrier or entry IMO.

Sure, but it's not one we can readily fix - the user hostility of
command line environments and the compromises we have to make to abide
by platform conventions are in the hands of operating system vendors,
and there's only so much we can do to paper over those distinctions
when user lock-in and putting barriers in the way of cross-device
portability is a core part of commercial OS vendors' business models.

This is a big part of why mobile client devices with cloud backends
are so popular, even for development purposes: they allow for a much
simpler developer experience that avoids decades of accumulated cruft
in the desktop operating system command line experience. Even there
though, you're faced with the fact that once you choose a provider,
whatever you do there will probably be locked into that provider and
not transferable elsewhere.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-06 Thread Nick Coghlan
On 6 November 2017 at 18:50, Stephan Houben <stephan...@gmail.com> wrote:
> Hi Michel,
>
> That's exactly why I proposed a `pip` function available from the Python
> prompt.
> I suppose you could still tell your students to copy/paste the following
> into their
> Python interpreter.
>
> def pip(args):
> import sys
> import subprocess
> subprocess.check_call([sys.executable, "-m", "pip"] + args.split())
> print("Please restart Python now to use installed or upgraded
> packages.")

Depending on where and how Python is installed, this may still not
work (while I'll grant that Linux users are more likely to already be
familiar with the command line than Windows and Mac OS X users, it's
still a non-trivial step from there to realising why "sudo pip
install" is almost always a bad idea)

> I suppose an alternative is to set up jupyterhub
>
> https://jupyterhub.readthedocs.io/en/latest/
>
> and let all your students just access that from a webbrowser.

Yep, and lots of teachers use services like PythonAnywhere,
trinket.io, and similar, precisely because the only thing the learners
need locally is a web browser. The main downside is that learning that
way isn't quite as transferable a skill, since it completely hides the
code packaging and distribution step. However, it's a good option when
the primary aim is to teach computational skills, and Python is just
the vehicle used for that purpose.

Software Carpentry starts out with the Anaconda distribution, as it
not only improves the cross-platform UX consistent situation, it also
deals with the external binary dependency problem (at least for the
core set of packages provided either natively or via conda-forge).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Looking for input to help with the pip situation

2017-11-06 Thread Nick Coghlan
On 6 November 2017 at 16:47, Michel Desmoulin <desmoulinmic...@gmail.com> wrote:
> I really want some people from this list to discuss here so we can find
> a way to either unify a bit the way we install and use pip, or find a
> way to express a tutorial that always works for people on the most
> popular platforms and spread the word so that any doc uses it.

https://docs.python.org/3/installing/#basic-usage is as close as we've
been able to get to that for the time being.

For Linux, you'll still need to do the initial "python3 -m venv" to
get your students out of the system Python.

I expect you'll also need an initial "py -m venv" for Windows users,
to get their PATH configured appropriately with both a "python"
command and any scripts they install from PyPI.

But the key point: do *NOT* try to teach without creating a virtual
environment as the first step, because it doesn't actually make
anything simpler, and in fact makes a lot of things harder and more
platform dependent.

The tutorial in the Python Packaging User Guide similarly starts with
venv creation: 
https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Moving typing out of the stdlib in Python 3.7?

2017-11-06 Thread Nick Coghlan
On 6 November 2017 at 16:42, Lukasz Langa <luk...@langa.pl> wrote:
>
>> On 5 Nov, 2017, at 10:30 PM, Michel Desmoulin <desmoulinmic...@gmail.com> 
>> wrote:
>>
>> Le 06/11/2017 à 07:07, Nick Coghlan a écrit :
>>
>>> It's the default on Unix as well - you have to do "make install
>>> ENSUREPIP=no" to avoid getting it. (And some distros also modify their
>>> Python installations so that pip is missing by default)
>>
>> On debian and derivatives (so Ubuntu) you need to install python-pip to
>> be able to use pip.
>>
>> Now it's annoying already. Because you have to write every tutorial to
>> include a special case for them. But at least it's not a required step
>> to run your program.
>>
>> However, if you do code using type hints and typing is not installed,
>> you can't even run the program without installing something. So we
>> finally have Python 3 by default on most Linux system, but still would
>> not be able to assume we can run a modern script on it.
>
> This is a valid concern. Although this particular problem is self-inflicted 
> by Debian, I can understand their rationale behind explicit packaging. They 
> need to have control over the entire package graph. I wonder if there's a way 
> in .deb to specify a required installed package. I'm not calling it a 
> "dependency" since obviously it would rather be "python3-typing" that depends 
> on "python3".

Fedora just lives with the circular dependency between python3 and
python3-pip, which ensures both are installed by default (this
arrangement allows "python3 -m venv" to still install pip, without
actually needing a second copy of pip inside the python3 package)

A bundled typing module that "python -m venv" installed by default
would probably require similar treatment.

> But even if Debian installs python3-typing by default, will "pip install -U 
> typing" be possible in this scenario? I guess it wouldn't be terrible if that 
> only worked in virtualenvs, although ideally it would work also for the raw 
> host installation.

"sudo pip install " remains a terrible idea on any distro,
because it leads to pip and the system package manager getting into a
fight over which tool is responsible for managing the affected files.

"pip install --user --upgrade typing" should work OK, though.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Moving typing out of the stdlib in Python 3.7?

2017-11-05 Thread Nick Coghlan
On 6 November 2017 at 09:08, Chris Angelico <ros...@gmail.com> wrote:
> On Mon, Nov 6, 2017 at 9:29 AM, Barry Scott <ba...@barrys-emacs.org> wrote:
>> If this is a mechanism that python kitting has then you would be able to
>> bundle other packages like requests or six as well as typing, but because
>> you can use pip to override the one shipped a user can optionally keep
>> up with the latest versions.
>
> If this were to happen, I would be inclined to put these "bootstrap"
> modules into their own directory in sys.path, after the rest of the
> stdlib. Then someone who's paranoid about stdlib shadowing could put
> pip-installed modules after the bulk of the stdlib (thus preventing
> any third-party package from overriding "import random", for instance)
> but still update modules that are specifically intended for updating;
> plus it'd mean you can get a directory listing of that, and go grab
> all the "blessed by python.org as an extension of the stdlib"
> packages.

When we say bundled, we mean bundled: the exact same bits you would
get from PyPI, installed the same way, and if you upgrade it system
wide, there's no trace of the one we bundled.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Moving typing out of the stdlib in Python 3.7?

2017-11-05 Thread Nick Coghlan
On 5 November 2017 at 23:30, Paul Moore <p.f.mo...@gmail.com> wrote:
> On 5 November 2017 at 10:48, Antoine Pitrou <solip...@pitrou.net> wrote:
>> On Sun, 5 Nov 2017 13:46:59 +1000
>> Nick Coghlan <ncogh...@gmail.com> wrote:
>>> * ensurepip gains the ability to also install bundled wheel files
>>
>> Why? Why wouldn't you put the wheel directly in site-packages on
>> install?
>
> I'm not quite sure what you mean? It needs to be "installed", in the
> sense of being unpacked into site-packages, and the ensurepip
> mechanism is already able to do that for pip and setuptools, so adding
> an extra wheel to install wouldn't be too hard. If we don't install
> like that, people won't be able to easily upgrade typing by just using
> "pip install --upgrade typing".
>
> Wheels don't support simply being added to sys.path the way that eggs
> did, if that's what you mean.

What Paul said here. While wheels *can* be designed to support
use-without-extraction (and pip's own wheel file is constructed that
way so you can use a pip wheel to install itself), the general design
principle is that we expect them to be installed prior to use, such
that they get proper PEP 376 metadata entries, and so that their
subcomponents end up in the right sysconfig directories for the
deployment environment.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Moving typing out of the stdlib in Python 3.7?

2017-11-04 Thread Nick Coghlan
On 5 November 2017 at 06:22, Guido van Rossum <gu...@python.org> wrote:
> On Sat, Nov 4, 2017 at 7:05 AM, Nick Coghlan <ncogh...@gmail.com> wrote:
>>
>> Perhaps typing could switch to being a bundled module, such that it
>> had its own version, independent of the Python standard library
>> version, but was still present by default in new installations?
>
>
> This is beginning to sound like the most attractive solution. We could
> possibly do away with typing_extensions. Are there precedents of how to
> bundle a module in this way? Or is it going to be another special case like
> pip?

You'd be blazing new trails, but you'd be blazing them with a
single-file pure Python module without any binary dependencies outside
CPython itself, which is the simplest possible precedent setting
scenario we could hope for.

I can think of a couple of possible approaches you could take,
depending on how you want to manage development on the typing module
itself.

= External dev =

* Typing moves entirely out of the CPython source tree, with a
separate issue tracker, repository, branch structure, etc (which you
already have)
* We add a "_bundled" directory to the CPython source tree in 3.7+ and
put a typing sdist archive there
* the release process PEP gains a "Confirm the bundled modules are up
to date" step
* the CPython build process is updated to use a venv to generate wheel
files from bundled sdists
* regrtest gains a "bundled" resource (and/or dedicated command line option)
* when asked to test bundled modules, regrtest spins up a test venv,
installs pip and the bundled modules, then runs the tests for those
modules
* ensurepip gains the ability to also install bundled wheel files
* the Windows and Mac OS X installers start including the typing wheel file

= In tree dev =

* Similar to external dev for testing and distribution
* Source code would stay in the main CPython tree and track CPython
branch structure
* The sdist file would be built by CPython's build process, rather
than being checked in

The external dev model is probably a better fit for your use case,
though, since you'd like something that you can readily keep
consistent across all supported 3.x versions (or at least 3.7+), and
that's harder to do when you have multiple copies of the source code
to keep in sync (vs having a single development branch where you run
your CI testing across all supported Python versions).

The external dev option also establishes a more useful precedent,
since we could use it to officially migrate ongoing distutils
maintenance into the setuptools project, and then bring it back via
bundling of setuptools. Similarly, PEP 434 (which already exempts IDLE
from the usual "No new features in maintenance releases" rules) could
potentially be switched over to handling IDLE as an independently
updated bundled application.

The above idea is somewhat similar to what I suggested for the
recommended modules list in
https://mail.python.org/pipermail/python-ideas/2017-October/047508.html,
but the difference is that to simplify the testing and installer
building process, we'd bundle a suitable source archive in the git
repo, rather than requiring PyPI access.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Proposal to change Python version release cycle

2017-11-04 Thread Nick Coghlan
On 5 November 2017 at 01:29, Wolfgang <tds...@mailbox.org> wrote:
> On 04.11.2017 16:01, Nick Coghlan wrote:
>> We're currently more likely to go the other direction, and stick with
>> the 3.x numbering for an extended period (potentially reaching 3.10,
>> 3.11, 3.12, etc), so that the ongoing disruption caused by the 2.x ->
>> 3.x transition has had a chance to settle down before we ask anyone to
>> start calling anything "Python 4".
>
> A good point but two digits minor version numbers have the possibility
> to break a lot code. There is a lot of stuff out where a single digit
> major version is assumed. Even the official Python build for windows
> with python27.dll, python36.dll can be problematic because the dot
> is omitted between numbers.
> Other do the same for compilation they concatenate only majorminor for a
> name.
> Then version 3.10 is the same as 31.0.
> Ok I know this will take a while.
> But for the first 2.7.10 version even there some other library code
> was broken because of such assumptions.

Aye, we're aware :)

We're not in a situation where we'll have any *good* options
available, so the question we're considering is "What do we think will
be the least bad approach?".

At our current release cadence, 3.7 will be in mid 2018, 3.8 in late
2019 or early 2020, and then 3.9 in mid 2021.

The open question will be what we call the release after that (in late
2022), with the main leading contenders being "4.0" (on the grounds
that so many changes will have accumulated since 2008's 3.0 release by
then that it makes sense to call them different major versions,
similar to the rationale the Linux kernel now uses for major version
updates), and "3.10" (on the grounds that the release won't be any
more different from 3.9 than 3.9 will be from 3.8). Other variants
(like making the major release number "40" or "2022", and using the
minor version field for some new purpose other than indicating
compatibility breaks in the compiler AST, interpreter opcode format,
code caching tags, and C ABI), tend to introduce the same pragmatic
questions that will already need to be considered in choosing between
the 3.10 and 4.0 alternatives.

It's not just the version numbering aesthetics that need to be
considered either - in addition to the point you raise around how the
Python version gets embedded in file path names (such that the 3-digit
form is technically ambiguous without a separator, and may break
parsers that are expecting exactly two digits), there are other
backwards compatibility concerns around how folks do version
compatibility checks based on sys.version and sys.version_info. Python
and CPython will be more than 3 decades old by 2022, and an ecosystem
can build up a *lot* of implicit assumptions regarding how a
platform's versioning scheme works in that kind of time frame :)

Personally, I doubt we'll make a firm decision on how we're going to
handle this until some time after 2.7 goes EOL in 2020, as by then
we'll necessarily have a better idea of how the various Linux distros
(including the LTS commercial ones) ended up handling the Python 2 ->
Python 3 switch, and the fact that the next release at that point will
be 3.9 making it eminently clear that we've run out of time to
continue postponing the question. We'll hopefully also have more
experience with folks relying on the stable runtime ABI, and hence
whether or not it might be beneficial to define new "py4" and "abi4"
compatibility tags for the binary wheel distribution format.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Proposal to change Python version release cycle

2017-11-04 Thread Nick Coghlan
On 5 November 2017 at 00:40, Wolfgang <tds...@mailbox.org> wrote:
>
>
> On 04.11.2017 14:29, Antoine Pitrou wrote:
>>
>>
>> Hello Wolfgang,
>>
>> On Sat, 4 Nov 2017 12:25:57 +0100 (CET)
>> tds...@mailbox.org wrote:
>>>
>>> Hello,
>>>
>>> one of my long standing ideas to improve Python is to adjust the
>>> release cycle and version number handling. In short, to simplify it.
>>
>>
>> There has been ample discussion in the past about changing our release
>> cycle one way or another. In short, the meta-problem is there are many
>> contradicting interests which would each favour a different solution to
>> the problem.  See for example this PEP (ultimately rejected):
>> https://www.python.org/dev/peps/pep-0407/
>>
>> and the discussion that ensued:
>>
>> https://mail.python.org/pipermail/python-dev/2012-January/thread.html#115591
>>
>> I haven't read your proposal in detail, but I suspect that it may be
>> vulnerable to some of the same objections.  The big objection being
>> that a significant part of our ecosystem (that is, to put it roughly,
>> the more corporate-minded segment, though I believe it is a
>> simplification and may include other segments, such as Debian stable
>> users and maintainers) doesn't want to deal more frequent feature
>> releases.
>
>
> I read this PEP and some of the discussion.
>
> The difference to my idea is not to propose a LTS version and feature
> preview releases.
>
> The simplest form of my change is to switch from today major.minor to simply
> major for the feature release cycle.

We're currently more likely to go the other direction, and stick with
the 3.x numbering for an extended period (potentially reaching 3.10,
3.11, 3.12, etc), so that the ongoing disruption caused by the 2.x ->
3.x transition has had a chance to settle down before we ask anyone to
start calling anything "Python 4".

While the problems Linux distros are facing with whether "python"
should refer to "python2" or "python3" are at least arguably
self-inflicted (especially for those that already dealt with the
Python 1.5.2 -> Python 2.0 migration back in the early 2000s), nobody
is really looking forward to having to figure out how to adjust to a
potential future Python 4.0 that invalidates all the current "python3"
based naming schemes that have been introduced to work around the fact
that Python 3.x needed to be parallel installable with Python 2.x
without breaking any existing Python 2.x applications. We're not even
sure yet when we're going to update PEP 394 to say that we think it's
reasonable for distros to start using "python" to mean "python3" (see
https://www.python.org/dev/peps/pep-0394/ and
https://github.com/python/redistributor-guide/issues/1 for more
discussion on the latter point).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Proposal to change Python version release cycle

2017-11-04 Thread Nick Coghlan
On 4 November 2017 at 23:29, Antoine Pitrou <solip...@pitrou.net> wrote:
>
> Hello Wolfgang,
>
> On Sat, 4 Nov 2017 12:25:57 +0100 (CET)
> tds...@mailbox.org wrote:
>> Hello,
>>
>> one of my long standing ideas to improve Python is to adjust the
>> release cycle and version number handling. In short, to simplify it.
>
> There has been ample discussion in the past about changing our release
> cycle one way or another. In short, the meta-problem is there are many
> contradicting interests which would each favour a different solution to
> the problem.  See for example this PEP (ultimately rejected):
> https://www.python.org/dev/peps/pep-0407/
>
> and the discussion that ensued:
> https://mail.python.org/pipermail/python-dev/2012-January/thread.html#115591

PEP 413 was another competing proposal from around the same time:
https://www.python.org/dev/peps/pep-0413/

Technically neither proposal has been formally Rejected, but they're
also Deferred/Withdrawn because we knew that if we *had* asked for an
explicit determination, the answer would have been "No, too high a
cost, for not enough of a demonstrated benefit" (and that hasn't
really changed in the past 5 years).

> I haven't read your proposal in detail, but I suspect that it may be
> vulnerable to some of the same objections.  The big objection being
> that a significant part of our ecosystem (that is, to put it roughly,
> the more corporate-minded segment, though I believe it is a
> simplification and may include other segments, such as Debian stable
> users and maintainers) doesn't want to deal more frequent feature
> releases.

It's not just redistributors that get affected - it's the
compatibility testing matrices for community projects as well.

With our current release cycles (and excluding the 2.7 LTS release
from consideration) we tend to have the following situation for the
3.x branches:

- 1 actively maintained version
- 2 or 3 security-fix only branches

This stems from the default commitment of security fixes ending around
5 years after an X.Y.0 release, and releases happening 18-24 months
apart:

* Month 0: X.Y.0 released
* Month 18: X.(Y+1).0 released
* Month 36: X.(Y+2).0 released
* Month 54: X.(Y+3).0 released
* Month 60: X.Y.Z goes end-of-life
* Month 72: X.(Y+4).0 released

That same pattern also held for the 2.x series until the 2.7 release
in 2010 (and it only changed then because that was the last 2.x
feature release).

The current year or so where the number of supported branches drops
down to only 3 means we have some scope to speed up the rate of
feature releases a bit (i.e. a release cadence of every 15 months
instead of every 18 still means the community compatibility testing
matrix consistently stays around 4 versions, or 5 if you're also
testing against the dev release), but going to 6 monthly version
updates means folks will either keep their test matrices the same as
they are now (increasing the odds of the standard-library-only updates
breaking things and that not being detected for some time), or else
feeling obliged to expand their test matrices to cover even more
concurrently supported versions. There are potential ways around both
of those problems, but they require making the defined support periods
for minor releases significantly shorter, unless they're the last
minor release before the next major release (which means that instead
of being simpler, these kinds of arrangements tend to end up being
*more* complicated than the "every feature release receives security
updates for 5 years" status quo).

So rather than making fundamental changes to the way Python is
versioned just to make standard library updates more readily available
on older base versions of Python, we've instead gone with a more needs
driven approach: making backport modules available for older versions
where we find it is beneficial to do so (e.g. contextlib2, unittest2,
importlib2).

While Python 2.7 is a major driver for that change in practice, the
benefits apply to older 3.x releases as well:

- the updated modules are available for all Python versions and
implementations where the packaging tools work (which is most of them)
- users can decide on a module-by-module basis whether they want the
baseline version or fast track updates
- those decisions are explicitly tracked in the project's dependency
metadata, rather than being implicit in the choice of deployment
platform

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] install pip packages from Python prompt

2017-11-03 Thread Nick Coghlan
On 3 November 2017 at 02:22, Ivan Levkivskyi <levkivs...@gmail.com> wrote:
> Just another random idea: What about simply having two menu items in IDLE:
>
> * Install/update package manager
> * Open package manager
>
> The first one will install the pipgui from PyPI (and pip if not already
> installed).
> The second one will run the GUI.
>
> This way it looks like pipgui can be simply published on PyPI without
> special-casing at all, or am I missing something?

This would also deal with the case where "ensurepip" hadn't been run
at install time for some reason.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] install pip packages from Python prompt

2017-11-02 Thread Nick Coghlan
On 2 November 2017 at 18:46, Nathaniel Smith <n...@pobox.com> wrote:

> But unfortuately this hasn't been standardized, and there's currently
> no way to do the lookup from the stdlib, so maybe this is not so
> helpful for IDLE...
>

The entry point file format was recently promoted to a PyPA
interoperability spec (without a PEP, as we documented it as-is, rather
than changing anything):
https://packaging.python.org/specifications/entry-points/

While the point about the standard library lacking the ability to read the
metadata for installed packages still stands, it's also not too hard to
implement a rudimentary version that just iterates over sys.path looking
for `entry_points.txt` files in `*.dist-info` subdirectories.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-11-01 Thread Nick Coghlan
On 2 November 2017 at 04:29, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> SPOILER ALERT! At the moment, Nick's statement is in fact **always** true
> in **all** cases (at least when ignoring untypical cases and some
> inaccuracies in phrasing). ​Another question is whether the statement
> **should** be true at all.​
> ​
>
> PyErr_CheckSignals(), the function that checks for pending signals, now
> **implicitly** uses the strictest possible memory-order requirement
> (SEQ_CST) for checking the `is_tripped` flag, a value which can be used to
> peek whether there are any pending signals. This means that two threads
> that call PyErr_CheckSignals can't even **check** the value of that flag
> at the same time, and they'll have to wait for each other and whatever the
> CPU hardware implementation does for cache synchronzation.
>

Nice, that's deeper than I went - I just assumed there was an
interlocked_increment in there somewhere, without checking whether or not
there were any optimised code paths that managed to avoid that call :)


> ​From a correctness point of view, that is absolutely great: if
> PyErr_CheckSignals() is called, it is guaranteed to notice a new signal
> regardles of how small the number of picoseconds after the `is_tripped`
> flag has been set.  But is that really important? Do we really need things
> to be slowed down by this? And do we want people to "optimize" code by
> avoiding signal checking?
>

It isn't signal handling latency that's the concern here, it's potentially
missing signals. Consider the case where we have 3 threads: A, B, C. A is
the main thread that will actually handle signals, B and C both happened to
receive them. We'll also assume  the two threads receive *different*
signals (otherwise they'll potentially get collapsed into one notification
regardless).

The scenario we want to avoid is having one or both of the signals set, but
is_tripped cleared. With an interlocked check (where both 0->1 and 1->0 are
memory barriers), that clearly can't happen. I suspect you're right that
this could also be achieved with a less strict memory sync requirement on
the 0->1 check, but that's much harder to reason about than simply limiting
the number of iterations we make through an iterator consumption loop
before checking for signals.


> The signals won't be caught until checked anyway, and as we've seen, one
> solution is to use a counter to determine if enough time has passed that
> another check for potential signals should happen. That does, however,
> raise the question of who should own the counter, and if it's OK for
> multiple threads to use the same counter. If yes, then would we be able to
> avoid slow atomic decrements (or increments)?
>
> But another solution might be to make a less strict but almost equivalent
> functionality with much less overhead. Something like this in a header file:
>
> static inline int PyErr_PROBE_SIGNALS() {
> static int volatile *flag = (int volatile *) _tripped;
> if (*flag) {
> return PyErr_CheckSignals();
> }
> else {
> return 0;
> }
> }
>
> ​Here, the flag is casted to volatile to force a check to happen each time
> from memory/cache. However, to make it more standard and to make sure it
> works with all compilers/platforms, it might be better to, instead of
> *flag, use an atomic load with "MEMORY_ORDER_RELAXED".​ Another thing is
> that `is_tripped`, which is currently declared as static inside
> signalmodule.c [4], should somehow be exposed in the API to make it
> available for the inline function in headers.
>
> ​This solution might be fast enough for a lot of cases, although still
> slightly slower than the counter approach, at least if the counter approach
> would completely avoid per-iteration memory access by requiring each
> function to own the counter that is used for this.
>

One thing I like about a nested inner loop is that it's easy to understand
the rationale for it *without* knowing any of the details of how memory
synchronisation works, as it's just:

- we want to check for signals regularly so the latency in interrupt
handling isn't too high
- PyErr_CheckSignals() is too expensive to call on every iteration
- so we only check every N iterations

Memory synchronisation then only comes up if someone asks why
"PyErr_CheckSignals" is expensive to call. And while it wouldn't surprise
at all if you're right and there are ways to make that call cheaper,
they're still never going to be cheaper than explicitly reducing the
frequency with which it is called.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] install pip packages from Python prompt

2017-10-31 Thread Nick Coghlan
On 1 November 2017 at 08:50, Terry Reedy <tjre...@udel.edu> wrote:

> In April 2016, after posting the idea to pydev list and getting 'go
> ahead's from Nick Coughlin and someone else, with no negatives, I approved
> Upendra Kumar's GSOC proposal to write a pip gui.  This was
> https://bugs.python.org/issue27051.  On June 20, Ned Deily and Nick
> Coughlin vetoed adding a pip gui anywhere in the stdlib since it depended
> on something not in the stdlib, and perhaps for other reasons I don't fully
> understand.
>

Clarifying the objection here (since the linked issue is a fairly long
one): what I'm against is tightly coupling the pip-gui development &
release process to the CPython development & release process when we don't
have any compelling reason to do so.

While PEP 434 provides a workaround that helps to keep IDLE consistent
across different support branches, it still isn't as robust a development
model as folks being able to install an application and try it out on
existing Python versions *before* we bundle it with a CPython release.
https://packaging.python.org/tutorials/distributing-packages/ provides a
general guide on how to publish new packages, and the combination of tox
and Travis CI makes it reasonably straightforward to run pre-merge CI
testing across multiple Python versions.

Given an independently released pip-gui on PyPI (with its own version
numbering and release cadence), then I'd be +1 on bundling that as an
optional IDLE addon, ensurepip style. Such a project could also lay the
foundation for switching IDLE itself to a similar bundling model, which
would allow the need for PEP 434 to be eliminated as well (since bundled
applications are already permitted to add new features in maintenance
releases).

Cheers,
Nick.

P.S. I'll also note that a useful feature Travis CI offers is the ability
to automate PyPI releases: https://docs.travis-ci.com/user/deployment/pypi/

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-31 Thread Nick Coghlan
On 1 November 2017 at 05:56, Guido van Rossum <gu...@python.org> wrote:

> On Tue, Oct 31, 2017 at 12:24 PM, MRAB <pyt...@mrabarnett.plus.com> wrote:
>
>> At least Python 3.6 is only 1 year/release behind, which is fine!
>>
>
> OK, so presumably that argument doesn't preclude inclusion in the 3.7 (or
> later) stdlib. I'm beginning to warm up to the idea again... Maybe we
> should just bite the bullet. Nick, what do you think? Is it worth a small
> PEP?
>

I'm personally still in favour of swapping out the current _sre based
implementation for a _regex based implementation (such that 3.7+ still only
contained a single regex engine, and the stdlib re module and a PyPI regex
backport module could still happily coexist), and a PEP + draft patch would
be the way to do that.

The framing of a PEP for that approach would be "Replace the regex engine
backing the re module" rather than "Add regex to the standard library". The
existing engine could then potentially be spun out as a new "sre" project
on PyPI, such that folks that *were* depending on _sre internals had access
to an upgrade path that didn't necessarily require them porting their code
to a new regex engine (the PEP author wouldn't have to commit to doing that
work - we'd just ask the PyPI admins to reserve the name in case there
proved to be demand for such a project).

However, I'm also not one of the folks that would be on the hook for
handling any compatibility regressions that were subsequently reported
against the 3.7 re module, so I'd also take my +1 with a rather large grain
of salt - it's easy to be positive about a plan when the potential
downsides don't affect me personally :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-31 Thread Nick Coghlan
On 1 November 2017 at 00:53, Guido van Rossum <gu...@python.org> wrote:

> On Tue, Oct 31, 2017 at 4:42 AM, Nick Coghlan <ncogh...@gmail.com> wrote:
>
>> On 31 October 2017 at 02:29, Guido van Rossum <gu...@python.org> wrote:
>>
>>> What's your proposed process to arrive at the list of recommended
>>> packages?
>>>
>>
>> I'm thinking it makes the most sense to treat inclusion in the
>> recommended packages list as a possible outcome of proposals for standard
>> library inclusion, rather than being something we'd provide a way to
>> propose specifically.
>>
>
> I don't think that gets you off the hook for a process proposal. We need
> some criteria to explain why a module should be on the recommended list --
> not just a ruling as to why it shouldn't be in the stdlib.
>

The developer guide already has couple of sections on this aspect:

* https://devguide.python.org/stdlibchanges/#acceptable-types-of-modules
* https://devguide.python.org/stdlibchanges/#requirements

I don't think either of those sections is actually quite right (since we've
approved new modules that wouldn't meet them), but they're not terrible as
a starting point in general, and they're accurate for the recommended
packages use case.


> We'd only use it in cases where a proposal would otherwise meet the
>> criteria for stdlib inclusion, but the logistics of actually doing so don't
>> work for some reason.
>>
>
> But that would exclude most of the modules you mention below, since one of
> the criteria is that their development speed be matched with Python's
> release cycle. I think there must be some form of "popularity" combined
> with "best of breed". In particular I'd like to have a rule that explains
> why flask and Django would never make the list. (I don't know what that
> rule is, or I would tell you -- my gut tells me it's something to do with
> having their own community *and* competing for the same spot.)
>

The developer guide words this as "The module needs to be considered
best-of-breed.". In some categories (like WSGI frameworks), there are
inherent trade-offs that mean there will *never* be a single best-of-breed
solution, since projects like Django, Flask, and Pyramid occupy
deliberately different points in the space of available design decisions.

Running the initial 5 proposals through that filter:
>>
>> * six: a cross-version compatibility layer clearly needs to be outside
>> the standard library
>>
>
> Hm... Does six still change regularly? If not I think it *would* be a
> candidate for actual stdlib inclusion. Just like we added u"..." literals
> to Python 3.4.
>

It still changes as folks porting new projects discover additional
discrepancies between the 2.x and 3.x standard library layouts and
behaviour (e.g. we found recently that the 3.x subprocess module's
emulation of the old commands module APIs actually bit shifts the status
codes relative to the 2.7 versions). The rate of change has definitely
slowed down a lot since the early days, but it isn't zero.

In addition, the only folks that need it are those that already care about
older versions of Python - if you can start with whatever the latest
version of Python is, and don't have any reason to support users still
running older version, you can happily pretend those older versions don't
exist, and hence don't need a compatibility library like six. As a separate
library, it can just gracefully fade away as folks stop depending on it as
they drop Python 2.7 support. By contrast, if we were to bring it into the
3.x standard library, then we'd eventually have to figure out when we could
deprecate and remove it again.


> * setuptools: we want to update this in line with the PyPA interop specs,
>> not the Python language version
>>
>
> But does that exclude stdlib inclusion? Why would those specs change, and
> why couldn't they wait for a new Python release?
>

The specs mainly change when we want to offer publishers new capabilities
while still maintaining compatibility with older installation clients (and
vice-versa: we want folks still running Python 2.7 to be able to publish
wheel files and use recently added metadata fields like
Description-Content-Type).

The reason we can't wait for new Python releases is because when we add
such things, we need them to work on *all* supported Python releases
(including 2.7 and security-release-only 3.x versions).

There are also other drivers for setuptools updates, which include:

- operating system build toolchain changes (e.g. finding new versions of
Visual Studio or XCode)
- changes to PyPI's operations (e.g. the legacy upload API getting turned
off due to persistent service stability problems, switching to HTTPS only
access)

With setuptools as 

Re: [Python-ideas] install pip packages from Python prompt

2017-10-31 Thread Nick Coghlan
On 31 October 2017 at 05:57, Alex Walters <tritium-l...@sdamon.com> wrote:

> > While I completely agree with this in principle, I think you
> > overestimate the average beginner.
>
> Nope.  I totally get that they don’t know what a shell or command prompt
> is.  THEY. NEED. TO. LEARN.  Hiding it is not a good idea for anyone.  If
> this is an insurmountable problem for the newbie, maybe they really
> shouldn’t be attempting to program.  This field is not for everyone.
>

We're not in the business of making judgements about who should and
shouldn't become Python programmers - we're in the business of making sure
that Python is accessible to as many people as possible by removing
irrelevant barriers to adoption, whether that's translating documentation
so folks can start learning with instructions in their native language, or
making it possible for them to defer learning the idiosyncrasies of the
Windows, Linux, and Mac OS X command line environments.

On the latter front, the details of the development interfaces offered by
traditional desktop operating systems may *never* be relevant to the new
generation of folks coming through that are learning to program by
manipulating remote coding environments on tablets and other app-centric
devices, just as most developers nowadays are able to get by without even
learning C, let alone any flavour of assembly language. Our role in this
process isn't to create future generations that think and work in exactly
the same ways we do, it's to enable them to discover new ways of working
that build on top of whatever we create.

Jupyter notebooks are a decent example of this, where the difference
between a Python statement and a "command line statement" is just an
exclamation mark at the beginning of the line - exactly where the backing
environment lives is mostly a hidden implementation detail from the user's
perspective.

Eclipse Che and other online coding environments are another case - there,
the "command line" is a different window inside the editor app (this is
also going to be a familiar option for heavy IDE users on traditional
desktop operating systems).

And putting it in those terms makes me think that we should explicitly
exclude the default REPL from consideration here, as we've long taken the
position that that *isn't* a good teaching environment, and you certainly
can't access it remotely without some kind of other service in front of it
to manage the network connection (even if that service is just ssh).

That means I now see a few potential RFEs from this thread:

1. An import system feature that allows a running Python program to report
a timestamp (with the same granularity as pyc file timestamp headers) for
*when* the currently loaded modules were last modified. This could be as
simple as a new `__mtime__`  attribute in each module to store that number.
2. A new importlib.util API to check for potentially out of date modules in
sys.modules (those where a freshly calculated module mtime doesn't match
the stored __mtime__ attribute)
3. Support in IDLE for Jupyter-style "!" commands
4. Having IDLE call that importlib API and warn about any stale modules
after each command line operation

The first two features would be about enabling learning environments to
more easily detect when the currently loaded modules may not match what's
actually on disk (hot reloaders already do this by watching for filesystem
changes, but we're currently missing a simpler polling based alternative
that will also pick up package updates).

The second two would be about enhancing IDLE's capabilities in this area,
as we *do* suggest that as a reasonable initial learning environment, even
though there are also plenty of alternatives out there now.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-31 Thread Nick Coghlan
On 31 October 2017 at 02:29, Guido van Rossum <gu...@python.org> wrote:

> What's your proposed process to arrive at the list of recommended packages?
>

I'm thinking it makes the most sense to treat inclusion in the recommended
packages list as a possible outcome of proposals for standard library
inclusion, rather than being something we'd provide a way to propose
specifically.

We'd only use it in cases where a proposal would otherwise meet the
criteria for stdlib inclusion, but the logistics of actually doing so don't
work for some reason.

Running the initial 5 proposals through that filter:

* six: a cross-version compatibility layer clearly needs to be outside the
standard library
* setuptools: we want to update this in line with the PyPA interop specs,
not the Python language version
* cffi: updates may be needed for PyPA interop specs, Python implementation
updates or C language definition updates
* requests: updates are more likely to be driven by changes in network
protocols and client platform APIs than Python language changes
* regex: we don't want two regex engines in the stdlib, transparently
replacing _sre would be difficult, and _sre is still good enough for most
purposes

Of the 5, I'd suggest that regex is the only one that could potentially
still make its way into the standard library some day - it would just
require someone with both the time and inclination to create a CPython
variant that used _regex instead of _sre as the default regex engine, and
then gathered evidence to show that it was "compatible enough" with _sre to
serve as the default engine for CPython.

For the first four, there are compelling arguments that their drivers for
new feature additions are such that their release cycles shouldn't ever be
tied to the rate at which we update the Python language definition.


> And is it really just going to be a list of names, or is there going to be
> some documentation (about the vetting, not about the contents of the
> packages) for each name?
>

I'm thinking a new subsection in
https://docs.python.org/devguide/stdlibchanges.html for "Recommended Third
Party Packages" would make sense, covering what I wrote above.

It also occurred to me that since the recommendations are independent of
the Python version, they don't really belong in the version specific
documentation.

While the Developer's Guide isn't really the right place for the list
either (except as an easier way to answer "Why isn't  in the standard
library?" questions), it could be a good interim option until I get around
to actually writing a first draft of
https://github.com/python/redistributor-guide/ (which I was talking to
Barry about at the dev sprint, but didn't end up actually creating any
content for since I went down a signal handling rabbit hole instead).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] install pip packages from Python prompt

2017-10-30 Thread Nick Coghlan
On 31 October 2017 at 02:06, Paul Moore <p.f.mo...@gmail.com> wrote:

> On 30 October 2017 at 15:53, Antoine Pitrou <solip...@pitrou.net> wrote:
> > On Tue, 31 Oct 2017 01:44:10 +1000
> > Nick Coghlan <ncogh...@gmail.com> wrote:
> >> (We'd want a real process restart, rather than emulating it by calling
> >> Py_Initialize & Py_Finalize multiple times, as not every module properly
> >> supports multiple initialise/finalise cycles within a single process,
> and
> >> module-specific quirks are exactly what we'd be trying to avoid by
> forcing
> >> an interpreter restart)
> >
> > The main difference, though, is that a notebook will reload and
> > replay all your session, while restarting the regular REPL will simply
> > lose all current work.  I think that makes the idea much less
> > appealing.
>

Right, but if you want an installation to work reliably, you're going to
lose that state anyway. Erik's original comment included the suggestion to
"give them an opportunity to cancel the
action in case they have any work they need to save", and I think some kind
of warning's going to be necessary no matter how we handle the restart.


> Also, on Windows, I believe that any emulation of execve either leaves
> the original process in memory, or has problems getting console
> inheritance right. It's been a long time since I worked at that level,
> and things may be better now, but getting a robust "restart this
> process" interface in Windows would need some care (that's one of the
> reasons the py launcher runs Python as a subprocess rather than doing
> any sort of exec equivalent).
>

As long as the standard streams are passed along correctly, whatever the py
launcher does would presumably be adequate for a REPL restart as well,
assuming we decided to go down that path.

It would also be reasonable to say that the regular REPL just issues a
warning that a restart might be needed, and it's only REPLs with a separate
client process that offer a way to restart the subprocess where code
actually executes.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-30 Thread Nick Coghlan
On 31 October 2017 at 00:28, Guido van Rossum <gu...@python.org> wrote:

> I just feel that when you're talking about an org like PayPal they can
> take care of themselves and don't need our help. They will likely have
> packages they want installed everywhere that would never make in on your
> list. So it feels this whole discussion is a distraction and a waste of
> time (yours, too).
>

Just because companies are big doesn't mean they necessarily have anyone
internally that's already up to speed on the specifics of recommended
practices in a sprawling open source community like Python's. The genesis
of this idea is that I think we can offer a more consistent initial
experience for those folks than "Here's PyPI and Google, y'all have fun
now" (and in so doing, help folks writing books and online tutorials to
feel more comfortable with the idea of assuming that libraries like
requests will be available in even the most restrictive institutional
environments that still allow the use of Python).

One specific situation this idea is designed to help with is the one where:

- there's a centrally managed Standard Operating Environment that dictates
what gets installed
- they've approved the python.org installers
- they *haven't* approved anything else yet

Now, a lot of large orgs simply won't get into that situation in the first
place, since their own supplier management rules will push them towards a
commercial redistributor, in which case they'll get their chosen
redistributor's preferred package set, which will then typically cover at
least a few hundred of the most popular PyPI packages.

But some of them will start from the narrower "standard library only"
baseline, and I spent enough time back at Boeing arguing for libraries to
be added to our approved component list to appreciate the benefits of
transitive declarations of trust ("we trust supplier X, they unambigously
state their trust in supplier Y, so that's an additional point in favour of
our also trusting supplier Y") when it comes time to make your case to your
supplier management organisation. Such declarations still aren'y always
sufficient, but they definitely don't hurt, and they sometimes help.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] install pip packages from Python prompt

2017-10-30 Thread Nick Coghlan
On 30 October 2017 at 20:35, Erik Bray <erik.m.b...@gmail.com> wrote:

> I should add--another case that is becoming extremely common is
> beginners learning Python for the first time inside the
> Jupyter/IPython Notebook.  And in my experience it can be very
> difficult for beginners to understand the connection between what's
> happening in the notebook ("it's in the web-browser--what does that
> have to do with anything on my computer??") and the underlying Python
> interpreter, file system, etc.  Being able to pip install from within
> the Notebook would be a big win.  This is already possible since
> IPython allows running system commands and it is possible to run the
> pip executable from the notebook, then manually restart the Jupyter
> kernel.
>
> It's not 100% clear to me how my proposal below would work within a
> Jupyter Notebook, so that would also be an angle worth looking into.
>

A few specific notes here:

1. As you say, this sort of already works in notebooks, since instructors
can say to run "!pip install requests" and then restart the language kernel.
2. We could probably replicate that style in IDLE, since that runs user
code in a subprocess, similar to the way Jupyter language kernels are
separate from the frontend client
3. We can't replicate it as readily in the regular REPL, since that runs
Python code directly in the current process, but even there I believe we
could potentially trigger a full process restart via execve (or the C++
style _execve on Windows)

(We'd want a real process restart, rather than emulating it by calling
Py_Initialize & Py_Finalize multiple times, as not every module properly
supports multiple initialise/finalise cycles within a single process, and
module-specific quirks are exactly what we'd be trying to avoid by forcing
an interpreter restart)

So the main missing piece if we went down that path would be to offer a way
to say from within the interpreter itself "Restart the current interactive
session". One possible approach to that would be to define a
RestartInterpreter subclass of SystemExit, which the interpreter would
intercept at around the same point where it checks for the PYTHONINSPECT
flag, and then initiate a graceful process shutdown and restart, rather
than a normal exit. We'd probably want that capability to be off by default
and enable it explicitly from the CPython CLI though, as otherwise it could
have some really annoying side effects in runtime embedding use cases.

I'm sure there'd be some thorny edge cases that would arise in trying to
make this work in practice, but at first glance, the general idea sounds
potentially feasible to me.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-29 Thread Nick Coghlan
On 30 October 2017 at 04:56, Guido van Rossum <gu...@python.org> wrote:

> The two use cases you describe (scripters and teachers) leave me luke-warm
> -- scripters live in the wild west and can just pip install whatever
> (that's what it means to be scripting)
>

For personal scripting, we can install whatever, but "institutional
scripting" isn't the same thing - there we're scripting predefined
"Standard Operating Environments", like those Mahmoud Hashemi describes for
PayPal at the start of
https://www.paypal-engineering.com/2016/09/07/python-packaging-at-paypal/

"Just use PyInstaller" isn't an adequate answer in large-scale environments
because of the "zlib problem": you don't want to have to rebuild and
redeploy the world to handle a security update in a low level frequently
used component, you want to just update that component and have everything
else pick it up dynamically.

While "Just use conda" is excellent advice nowadays for any organisation
contemplating defining their own bespoke Python SOE (hence Mahmoud's post),
if that isn't being driven by the folks that already maintain the SOE (as
happened in PayPal's case) convincing an org to add a handful of python-dev
endorsed libraries to an established SOE is going to be easier than
rebasing their entire Python SOE on conda.


> and teachers tend to want a customized bundle anyway -- let the edu world
> get together and create their own recommended bundle.
>
> As long as it's not going to be bundled, i.e. there's just going to be
> some list of packages that we recommend to 3rd party repackagers, then I'm
> fine with it. But they must remain clearly marked as 3rd party packages in
> whatever docs we provide, and live in site-packages.
>

Yep, that was my intent, although it may not have been clear in my initial
proposal. I've filed two separate RFEs in relation to that:

* Documentation only: https://bugs.python.org/issue31898
* Regression testing resource: https://bugs.python.org/issue31899

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Composition over Inheritance

2017-10-29 Thread Nick Coghlan
On 29 October 2017 at 21:44, Soni L. <fakedme...@gmail.com> wrote:

> ORMs use this kind of descriptor based composition management extensively
> in order to reliably model database foreign key relationships in a way
> that's mostly transparent to users of the ORM classes.
>
>
> And this is how you miss the whole point of being able to dynamically
> add/remove arbitrary components on objects you didn't create, at runtime.
>

You can already do that by adding new properties to classes
post-definition, or by changing __class__ to refer to a different type, or
by wrapping objects in transparent proxy types the way wrapt does.

We *allow* that kind of thing, because it's sometimes beneficial in order
to get two libraries to play nicely together at runtime without having to
patch one or the other. However, it's a last resort option that you use
when you've exhausted the other more maintainable alternatives, not
something we actually want to encourage.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-29 Thread Nick Coghlan
On 29 October 2017 at 15:16, Guido van Rossum <gu...@python.org> wrote:

> Why? What's wrong with pip install?
>

At a technical level, this would just be a really thin wrapper around 'pip
install' (even thinner than ensurepip in general, since these libraries
*wouldn't* be bundled for offline installation, only listed by name).


> Why complicate things? Your motivation is really weak here. "beneficial"?
> "difficult cases"?
>

The main recurring problems with "pip install" are a lack of
discoverability and a potential lack of availability (depending on the
environment).

This then causes a couple of key undesirable outcomes:

- folks using Python as a teaching language have to choose between teaching
with just the standard library APIs, requiring that learners restrict
themselves to a particular preconfigured learning environment, or make a
detour into package management tools in order to ensure learners have
access to the APIs they actually want to use (this isn't hypothetical - I
was a technical reviewer for a book that justified teaching XML-RPC over
HTTPS+JSON on the basis that xmlrpc was in the standard library, and
requests wasn't)
- folks using Python purely as a scripting language (i.e without app level
dependency management) may end up having to restrict themselves to the
standard library API, even when there's a well-established frequently
preferred alternative for what they're doing (e.g. requests for API
management, regex for enhanced regular expressions)

The underlying problem is that our reasons for omitting these particular
libraries from the standard library relate mainly to publisher side
concerns like the logistics of ongoing bug fixing and support, *not* end
user concerns like software reliability or API usability. This means that
if educators aren't teaching them, or redistributors aren't providing them,
then they're actively doing their users a disservice (as opposed to other
cases like web frameworks and similar, where there are multiple competing
options, you're only going to want one of them in any given application,
and the relevant trade-offs between the available options depend greatly on
exactly what you're doing)

Now, the Python-for-data-science community have taken a particular
direction around handling this, and there's an additional library set
beyond the standard library that's pretty much taken for granted in a data
science context. While conda has been the focal point for those efforts
more recently, it started a long time ago with initiatives like Python(x,
y) and the Enthought Python Distribution.

Similarly, initiatives like Raspberry Pi are able to assume a particular
learning environment (Raspbian in the Pi's case), rather than coping with
arbitrary starting points.

Curated lists like the "awesome-python" one that Stephan linked don't
really help that much with the discoverability problem, since they become
just another thing for people to learn: How do they find out such lists
exist in the first place? Given such a list, how do they determine if the
recommendations it offers are actually relevant to their needs? Since
assessing a published package API against your needs as a user is a skill
that has to be learned like any other, it can be a lot easier to get
started in a more prescriptive environment that says "This is what you have
to work with for now, we'll explain more about your options for branching
out later".

The proposal in this thread thus stems from asking the question "Who is
going to be best positioned to offer authoritative advice on which third
party modules may be preferable to their standard library counterparts for
end users of Python?" and answering it with "The standard library module
maintainers that are already responsible for deciding whether or not to
place appropriate See Also links in the module documentation".

All the proposal does is to suggest taking those existing recommendations
from the documentation and converting them into a more readibly executable
form.

I'm not particularly wedded to any particular approach to making the
recommendations available in a more machine-friendly form, though - it's
just the "offer something more machine friendly than scraping the docs for
recommendation links" aspect that I'm interested in. For example, we could
skip touching ensurepip or venv at all, and instead limit this to a
documentation proposal to collect these recommendations from the
documentation, and publish them within the `venv` module docs as a
"recommended-libraries.txt" file (using pip's requirements.txt format).
That would be sufficient to allow straightforward 3rd party automation,
without necessarily committing to providing such automation ourselves.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Pytho

Re: [Python-ideas] Composition over Inheritance

2017-10-28 Thread Nick Coghlan
On 29 October 2017 at 12:25, Brendan Barnwell <brenb...@brenbarn.net> wrote:

> On 2017-10-28 19:13, Soni L. wrote:
>
>> And to have all cars have engines, you'd do:
>>
>> class Car:
>> def __init__(self, ???):
>>   self[Engine] = GasEngine()
>>
>> car = Car()
>> car[Engine].kickstart() # kickstart gets the car as second argument.
>>
>> And if you can't do that, then you can't yet do what I'm proposing, and
>> thus the proposal makes sense, even if it still needs some refining...
>>
>
> As near as I can tell you can indeed do that, although it's still
> not clear to me why you'd want to.  You can give Car a __getitem__ that
> on-the-fly generates an Engine object that knows which Car it is attached
> to, and then you can make Engine.kickstart a descriptor that knows which
> Engine it is attached to, and from that can figure out which Car it is
> attached to.
>

Right, I think a few different things are getting confused here related to
how different folks use composition.

For most data modeling use cases, the composition model you want is either
a tree or an acyclic graph, where the subcomponents don't know anything
about the whole that they're a part of. This gives you good component
isolation, and avoids circular dependencies.

However, for other cases, you *do* want the child object to be aware of the
parent - XML etrees are a classic example of this, where we want to allow
navigation back up the tree, so each node gains a reference to its parent
node. This often takes the form of a combination of delegation
(parent->child references) and dependency inversion (child->parent
reference).

For the car/engine example, this relates to explicitly modeling the
relationship whereby a car can have one or more engines (but the engine may
not currently be installed), while an engine can be installed in at most
one car at any given point in time.

You don't even need the descriptor protocol for that though, you just need
the subcomponent to accept the parent reference as a constructor parameter:

class Car:
  def __init__(self, engine_type):
self.engine = engine_type(self)

However, this form of explicit dependency inversion wouldn't work as well
if you want to be able to explicitly create an "uninstalled engine"
instance, and then pass the engine in as a parameter to the class
constructor:

class Car:
  def __init__(self, engine):
self.engine = engine # How would we ensure the engine is marked as
installed here?

As it turns out, Python doesn't need new syntax for this either, as it's
all already baked into the regular attribute access syntax, whereby
descriptor methods get passed a reference not only to the descriptor, but
*also* to the object being accessed:
https://docs.python.org/3/howto/descriptor.html#descriptor-protocol

And then the property builtin lets you ignore the existence of the
descriptor object entirely, and only care about the original object,
allowing the above example to be written as:

class Car:
  def __init__(self, engine):
self.engine = engine # This implicitly marks the engine as installed

  @property
  def engine(self):
  return self._engine

  @engine.setter
  def engine(self, engine):
 if engine is not None:
 if self._engine is not None:
 raise RuntimeError("Car already has an engine installed")
 if engine._car is not None:
 raise RuntimeError("Engine is already installed in another
car")
 engine._car = self
 self._engine = engine

 car = Car(GasEngine())

ORMs use this kind of descriptor based composition management extensively
in order to reliably model database foreign key relationships in a way
that's mostly transparent to users of the ORM classes.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Defining an easily installable "Recommended baseline package set"

2017-10-28 Thread Nick Coghlan
Over on python-dev, the question of recommending MRAB's "regex" module over
the standard library's "re" module for more advanced regular expressions
recently came up again.

Because of various logistical issues and backwards compatibility risks,
it's highly unlikely that we'll ever be able to swap out the current _sre
based re module implementation in the standard library for an
implementation based on the regex module.

At the same time, it would be beneficial to have a way to offer an even
stronger recommendation to redistributors that we think full-featured
general purpose Python scripting environments should offer the regex module
as an opt-in alternative to the baseline re feature set, since that would
also help with other currently difficult cases like the requests module.

What I'm thinking is that we could make some relatively simple additions to
the `ensurepip` and `venv` modules to help with this:

1. Add a ensurepip.RECOMMENDED_PACKAGES mapping keyed by standard library
module names containing dependency specifiers for recommended third party
packages for particular tasks (e.g. "regex" as an enhanced alternative to
"re", "requests" as an enhanced HTTPS-centric alternative to
"urllib.request")

2. Add a new `install_recommended` boolean flag to ensurepip.bootstrap

3. Add a corresponding `--install-recommended flag to the `python -m
ensurepip` CLI

4. Add a corresponding `--install-recommended flag to the `python -m venv`
CLI (when combined with `--without-pip`, this would run pip directly from
the bundled wheel file to do the installations)

We'd also need either a new informational PEP or else a section in the
developer guide to say that the contents of
`ensurepip.RECOMMENDED_PACKAGES` are up to the individual module
maintainers (hence keying the mapping by standard library module name,
rather than having a single flat list for the entire standard library).

For redistributors with weak dependency support, these reference
interpreter level recommendations could become redistributor level
recommendations. Redistributors without weak dependency support could still
make a distinction between "default" installations (which would include
them) and "minimal" installations (which would exclude them).

Folks writing scripts and example code for independent distribution (i.e.
no explicitly declared dependencies) could then choose between relying on
just the standard library (as now), or on the standard library plus
independently versioned recommended packages.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Dollar operator suggestion

2017-10-26 Thread Nick Coghlan
On 27 October 2017 at 02:23, Chris Barker <chris.bar...@noaa.gov> wrote:

>
>
> On Thu, Oct 26, 2017 at 6:32 AM, Paul Moore <p.f.mo...@gmail.com> wrote:
>
>>
>> Procedural languages, and Python in particular, simply don't work like
>> that. Functions have arbitrary numbers of arguments,
>
>
> And can return an arbitrary number of values. OK, technically a single
> tuple of values, but that does complicate the whole simple chaining thing.
>
> In short -- Python is not a functional language, even though is supports a
> number of functional idioms.
>

https://bugs.python.org/issue1506122 has a brief discussion of the
non-syntactic variant of this proposal:

functools.compose(len, set, str)(foo) => -> len(set(str(foo)))

The main concerns that resulted in the suggestion being rejected are:

* it isn't clear to folks that aren't already familiar with FP why the call
order for the composed functions should be right to left
* it isn't clear why every function other than the rightmost one must
accept a single positional arg
* it isn't clear why every function other than the leftmost one must return
a single result

And it doesn't make sense to provide something more general, because if
you're writing genuinely functional code, you do tend to abide by those
restrictions.

So given that our position is "We don't even want to add this to the
standard library, because the learning curve for using it successfully is
too steep", it's even less likely we'd be willing to add syntax for the
operation.

By contrast, "FP-for-Python" libraries like toolz [1] can make familiarity
with those kinds of concepts and a willingness to abide by the related
conventions a pre-requisite for using them. It's just opt-in, the same way
that learning to define your own classes (rather than importing existing
ones defined elsewhere) is opt-in.

Cheers,
Nick.

[1] https://toolz.readthedocs.io/en/latest/

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-18 Thread Nick Coghlan
On 19 October 2017 at 08:34, Greg Ewing <greg.ew...@canterbury.ac.nz> wrote:

> Nick Coghlan wrote:
>
>> since breaking up the current single level loops as nested loops would be
>> a pre-requisite for allowing these APIs to check for signals while they're
>> running while keeping the per-iteration overhead low
>>
>
> Is there really much overhead? Isn't it just checking a flag?
>

It's checking an atomically updated flag, so it forces CPU cache
synchronisation, which means you don't want to be doing it on every
iteration of a low level loop.

However, reviewing Serhiy's PR reminded me that PyErr_CheckSignals()
already encapsulates the "Should this thread even be checking for signals
in the first place?" logic, which means the code change to make the
itertools iterators inherently interruptible with Ctrl-C is much smaller
than I thought it would be. That approach is also clearly safe from an
exception handling point of view, since all consumer loops already need to
cope with the fact that itr.__next__() may raise arbitrary exceptions
(including KeyboardInterrupt).

So that change alone already offers a notable improvement, and combining it
with a __length_hint__() implementation that keeps container constructors
from even starting to iterate would go even further towards making the
infinite iterators more user friendly.

Similar signal checking changes to the consumer loops would also be
possible, but I don't think that's an either/or decision: changing the
iterators means they'll be interruptible for any consumer, while changing
the consumers would make them interruptible for any iterator, and having
checks in both the producer & the consumer merely means that you'll be
checking for signals twice every 65k iterations, rather than once.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 22:53, Serhiy Storchaka <storch...@gmail.com> wrote:

> 18.10.17 13:22, Nick Coghlan пише:
>
>> 2.. These particular cases can be addressed locally using existing
>> protocols, so the chances of negative side effects are low
>>
>
> Only the particular case `count() in count()` can be addressed without
> breaking the following examples:
>

You're right, the potential impact on objects with weird __eq__
implementations would mean that even the `__contains__` approach would
require deprecation warnings for the APIs that allow short-circuiting. So
we can discard it in favour of exploring the "Can we make a beneficial
improvement via __length_hint__?" question.


> 3. The total amount of code involved is likely to be small (a dozen or so
>> lines of C, a similar number of lines of Python in the tests) in
>> well-isolated protocol functions, so the chances of introducing future
>> maintainability problems are low
>>
>
> It depends on what you want to achieve. Just prevent an infinity loop in
> `count() in count()`, or optimize `int in count()`, or optimize more
> special cases.
>

My interest lies specifically in reducing the number of innocent looking
ways we offer to provoke uninterruptible infinite loops or unbounded memory
consumption.


> 4. We have a potential contributor who is presumably offering to do the
>> work (if that's not the case, then the question is moot anyway until a
>> sufficiently interested volunteer turns up)
>>
>
> Maintaining is more than writing an initial code.
>

Aye, that's why the preceding point was to ask how large a change we'd be
offering to maintain indefinitely, and how well isolated that change would
be.


> If we were to do that, then we *could* make the solution to the reported
>> problem more general by having all builtin and standard library operations
>> that expect to be working with finite iterators (the containment testing
>> fallback, min, max, sum, any, all, functools.reduce, etc) check for a
>> length hint, even if they aren't actually pre-allocating any memory.
>>
>
> This will add a significant overhead for relatively short (hundreds of
> items) sequences. I already did benchmarking for similar cases in the past.


I did wonder about that, so I guess the baseline zero-risk enhancement idea
would be to only prevent the infinite loop in cases that already request a
length hint as a memory pre-allocation check. That would reduce the
likelihood of the most painful case (grinding the machine to a halt),
without worrying about the less painful cases (which will break the current
process, but the rest of the machine will be fine).

Given that, adding TypeError raising __length_hint__ implementations to
itertools.count(), itertools.cycle(), and itertools.repeat() would make
sense as an independent RFE, without worrying about any APIs that don't
already check for a length hint.

A more intrusive option would then be to look at breaking the other tight
iteration loops into two phases, such that checking for potentially
infinite iterators could be delayed until after the first thousand
iterations or so. That option is potentially worth exploring anyway, since
breaking up the current single level loops as nested loops would be a
pre-requisite for allowing these APIs to check for signals while they're
running while keeping the per-iteration overhead low (only one
pre-requisite of many though, and probably one of the easier ones).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Memory limits [was Re: Membership of infinite iterators]

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 22:51, Stefan Krah <ste...@bytereef.org> wrote:

> On Wed, Oct 18, 2017 at 10:43:57PM +1000, Nick Coghlan wrote:
> > Per-process memory quotas *can* help avoid this, but enforcing them
> > requires that every process run in a resource controlled sandbox. Hence,
> > it's not a coincidence that mobile operating systems and container-based
> > server environments already work that way, and the improved ability to
> cope
> > with misbehaving applications is part of why desktop operating systems
> > would like to follow the lead of their mobile and server counterparts :)
>
> Does this also fall under the sandbox definition?
>
> $ softlimit -m 10 python3
>

Yeah, Linux offers good opt-in tools for this kind of thing, and the
combination of Android and containerised server environments means they're
only getting better. But we're still some time away from it being routine
for your desktop to be well protected from memory management misbehaviour
in arbitrary console or GUI applications.

The resource module (which Steven mentioned in passing) already provides
opt-in access to some of those features from within the program itself:
https://docs.python.org/3/library/resource.html

For example:

>>> import sys, resource
>>> data = bytes(2**32)
>>> resource.setrlimit(resource.RLIMIT_DATA, (2**31, sys.maxsize))
>>> data = bytes(2**32)
Traceback (most recent call last):
  File "", line 1, in 
MemoryError
>>> resource.setrlimit(resource.RLIMIT_DATA, (sys.maxsize, sys.maxsize))
>>> data = bytes(2**32)

(Bulk memory allocations start failing on my machine somewhere between
2**33 and 2**34, which is about what I'd expect, since it has 8 GiB of
physical RAM installed)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Memory limits [was Re: Membership of infinite iterators]

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 21:38, Steven D'Aprano <st...@pearwood.info> wrote:

> > But should it be fixed in list or in count?
>
> Neither. There are too many other places this can break for it to be
> effective to try to fix each one in place.
>

> e.g. set(xrange(2**64)), or tuple(itertools.repeat([1]))
>

A great many of these call operator.length_hint() these days in order to
make a better guess as to how much memory to pre-allocate, so while that
still wouldn't intercept everything, it would catch a lot of them.


> Rather, I think we should set a memory limit that applies to the whole
> process. Once you try to allocate more memory, you get an MemoryError
> exception rather than have the OS thrash forever trying to allocate a
> terabyte on a 4GB machine.
>
> (I don't actually understand why the OS can't fix this.)
>

Trying to allocate enormous amounts of memory all at once isn't the
problem, as that just fails outright with "Not enough memory":

>>> data = bytes(2**62)
Traceback (most recent call last):
  File "", line 1, in 
MemoryError

The machine-killing case is repeated allocation requests that the operating
system *can* satisfy, but require paging almost everything else out of RAM.
And that's exactly what "list(infinite_iterator)" entails, since the
interpreter will make an initial guess as to the correct size, and then
keep resizing the allocation to 125% of its previous size each time it
fills up (or so - I didn't check the current overallocation factor) .

Per-process memory quotas *can* help avoid this, but enforcing them
requires that every process run in a resource controlled sandbox. Hence,
it's not a coincidence that mobile operating systems and container-based
server environments already work that way, and the improved ability to cope
with misbehaving applications is part of why desktop operating systems
would like to follow the lead of their mobile and server counterparts :)

So here is my suggestion:
>
> 1. Let's add a function in sys to set the "maximum memory" available,
> for some definition of memory that makes the most sense on your
> platform. Ordinary Python programmers shouldn't have to try to decipher
> the ulimit interface.
>

Historically, one key reason we didn't do that was because the `PyMem_*`
APIs bypassed CPython's memory allocator, so such a limit wouldn't have
been particularly effective.

As of 3.6 though, even bulk memory allocations pass through pymalloc,
making a Python level memory allocation limit potentially more viable
(since it would pick up almost all of the interpeter's own allocations,
even if it missed those in extension modules):
https://docs.python.org/dev/whatsnew/3.6.html#optimizations

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 20:39, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> On Oct 18, 2017 13:29, "Nick Coghlan" <ncogh...@gmail.com> wrote:
>
> On 18 October 2017 at 19:56, Koos Zevenhoven <k7ho...@gmail.com> wrote:
>
>> I'm unable to reproduce the "uninterruptible with Ctrl-C"​ problem with
>> infinite iterators. At least itertools doesn't seem to have it:
>>
>> >>> import itertools
>> >>> for i in itertools.count():
>> ... pass
>> ...
>>
>
> That's interrupting the for loop, not the iterator. This is the test case
> you want for the problem Jason raised:
>
> >>> "a" in itertools.count()
>
> Be prepared to suspend and terminate the affected process, because Ctrl-C
> isn't going to help :)
>
>
> I'm writing from my phone now, cause I was dumb enough to try list(count())
>

Yeah, that's pretty much the worst case example, since the machine starts
thrashing memory long before it actually gives up and starts denying the
allocation requests :(


> But should it be fixed in list or in count?
>

That one can only be fixed in count() - list already checks
operator.length_hint(), so implementing itertools.count.__length_hint__()
to always raise an exception would be enough to handle the container
constructor case.

The open question would then be the cases that don't pre-allocate memory,
but still always attempt to consume the entire iterator:

min(itr)
max(itr)
sum(itr)
functools.reduce(op, itr)
"".join(itr)

And those which *may* attempt to consume the entire iterator, but won't
necessarily do so:

x in itr
any(itr)
all(itr)

The items in the first category could likely be updated to check
length_hint and propagate any errors immediately, since they don't provide
any short circuiting behaviour - feeding them an infinite iterator is a
guaranteed uninterruptible infinite loop, so checking for a length hint
won't break any currently working code (operator.length_hint defaults to
returning zero if a type doesn't implement __length_hint__).

I'm tempted to say the same for the APIs in the latter category as well,
but their short-circuiting semantics mean those can technically have
well-defined behaviour, even when given an infinite iterator:

>>> any(itertools.count())
True
>>> all(itertools.count())
False
>>> 1 in itertools.count()
True

It's only the "never short-circuits" branch that is ill-defined for
non-terminating input. So for these, the safer path would be to emit
DeprecationWarning if length_hint fails in 3.7, and then pass the exception
through in 3.8+.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 19:56, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> I'm unable to reproduce the "uninterruptible with Ctrl-C"​ problem with
> infinite iterators. At least itertools doesn't seem to have it:
>
> >>> import itertools
> >>> for i in itertools.count():
> ... pass
> ...
>

That's interrupting the for loop, not the iterator. This is the test case
you want for the problem Jason raised:

>>> "a" in itertools.count()

Be prepared to suspend and terminate the affected process, because Ctrl-C
isn't going to help :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-18 Thread Nick Coghlan
On 18 October 2017 at 03:39, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> On Tue, Oct 17, 2017 at 5:26 PM, Serhiy Storchaka <storch...@gmail.com>
> wrote:
>
>> 17.10.17 17:06, Nick Coghlan пише:
>>
>>> Keep in mind we're not talking about a regular loop you can break out of
>>> with Ctrl-C here - we're talking about a tight loop inside the interpreter
>>> internals that leads to having to kill the whole host process just to get
>>> out of it.
>>>
>>
>> And this is the root of the issue. Just let more tight loops be
>> interruptible with Ctrl-C, and this will fix the more general issue.
>>
>>
> ​Not being able to interrupt something with Ctrl-C in the repl or with the
> interrupt command in Jupyter notebooks is definitely a thing I sometimes
> encounter. A pity I don't remember when it happens, because I usually
> forget it very soon after I've restarted the kernel and continued working.
> But my guess is it's usually not because of an infinite iterator.
>

Fixing the general case is hard, because the assumption that signals are
only checked between interpreter opcodes is a pervasive one throughout the
interpreter internals.  We certainly *could* redefine affected C APIs as
potentially raising KeyboardInterrupt (adjusting the signal management
infrastructure accordingly), and if someone actually follows through and
implements that some day, then the argument could then be made that given
such change, it might be reasonable to drop any a priori guards that we
have put in place for particular *detectable* uninterruptible infinite
loops.

However, that's not the design question being discussed in this thread. The
design question here is "We have 3 known uninterruptible infinite loops
that are easy to detect and prevent. Should we detect and prevent them?".
"We shouldn't allow anyone to do this easy thing, because it would be
preferable for someone to instead do this hard and complicated thing that
nobody is offering to do" isn't a valid design argument in that situation.

And I have a four step check for that which prompts me to say "Yes, we
should detect and prevent them":

1. Uninterruptible loops are bad, so having fewer of them is better
2. These particular cases can be addressed locally using existing
protocols, so the chances of negative side effects are low
3. The total amount of code involved is likely to be small (a dozen or so
lines of C, a similar number of lines of Python in the tests) in
well-isolated protocol functions, so the chances of introducing future
maintainability problems are low
4. We have a potential contributor who is presumably offering to do the
work (if that's not the case, then the question is moot anyway until a
sufficiently interested volunteer turns up)

As an alternative implementation approach, the case could also be made that
these iterators should be raising TypeError in __length_hint__, as that
protocol method is explicitly designed to be used for finite container
pre-allocation. That way things like "list(itertools.count())" would fail
immediately (similar to the way "list(range(10**100))" already does) rather
than attempting to consume all available memory before (hopefully) finally
failing with MemoryError.

If we were to do that, then we *could* make the solution to the reported
problem more general by having all builtin and standard library operations
that expect to be working with finite iterators (the containment testing
fallback, min, max, sum, any, all, functools.reduce, etc) check for a
length hint, even if they aren't actually pre-allocating any memory. Then
the general purpose marker for "infinite iterator" would be "Explicitly
defines __length_hint__ to raise TypeError", and it would prevent a priori
all operations that attempted to fully consume the iterator.

That more general approach would cause some currently "working" code (like
"any(itertools.count())" and "all(itertools.count())", both of which
consume at most 2 items from the iterator) to raise an exception instead,
and hence would require the introduction of a DeprecationWarning in 3.7
(where the affected APIs would start calling length hint, but suppress any
exceptions from it), before allowing the exception to propagate in 3.8+.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 17 October 2017 at 23:17, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> On Tue, Oct 17, 2017 at 2:46 PM, Serhiy Storchaka <storch...@gmail.com>
> wrote:
>
>> 17.10.17 14:10, Nick Coghlan пише:
>>
>>> 1. It's pretty easy to write "for x in y in y" when you really meant to
>>> write "for x in y", and if "y" is an infinite iterator, the "y in y" part
>>> will become an unbreakable infinite loop when executed instead of the
>>> breakable one you intended (especially annoying if it means you have to
>>> discard and restart a REPL session due to it, and that's exactly where that
>>> kind of typo is going to be easiest to make)
>>>
>>
>> I think it is better to left this on linters.
>
>
> ​Just to note that there is currently nothing that would prevent making
> `for x in y in z`​ a syntax error. There is nothing meaningful that it
> could do, really, because y in z can only return True or False (or raise an
> Exception or loop infinitely).
>

That was just an example of one of the ways we can accidentally end up
writing "x in y" at the REPL, where "y" is an infinite iterator, since it's
the kind that's specific to "x in y", whereas other forms (like
accidentally using the wrong variable name) also apply to other iterator
consuming APIs (like the ones Serhiy mentioned).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 17 October 2017 at 21:46, Serhiy Storchaka <storch...@gmail.com> wrote:

> 17.10.17 14:10, Nick Coghlan пише:
>
>> 1. It's pretty easy to write "for x in y in y" when you really meant to
>> write "for x in y", and if "y" is an infinite iterator, the "y in y" part
>> will become an unbreakable infinite loop when executed instead of the
>> breakable one you intended (especially annoying if it means you have to
>> discard and restart a REPL session due to it, and that's exactly where that
>> kind of typo is going to be easiest to make)
>>
>
> I think it is better to left this on linters. I never encountered this
> mistake and doubt it is common. In any case the first execution of this
> code will expose the mistake.
>

People don't run linters at the REPL, and it's at the REPL where
accidentally getting an unbreakable infinite loop is most annoying.

Keep in mind we're not talking about a regular loop you can break out of
with Ctrl-C here - we're talking about a tight loop inside the interpreter
internals that leads to having to kill the whole host process just to get
out of it.


> 2. Containment testing already has a dedicated protocol so containers can
>> implement optimised containment tests, which means it's also trivial for an
>> infinite iterator to intercept and explicitly disallow containment checks
>> if it chooses to do so
>>
>
> But this has non-zero maintaining cost. As the one who made many changes
> in itertools.c I don't like the idea of increasing its complexity for
> optimizing a pretty rare case.
>

It's not an optimisation, it's a UX improvement for the interactive prompt.
The maintenance burden should be low, as it's highly unlikely we'd ever
need to change this behaviour again in the future (I do think deprecating
the success case would be more trouble than it would be worth though).


> And note that the comparison can have side effect. You can implement the
> optimization of `x in count()` only for the limited set of builtin types.
> For example `x in range()` is optimized only for exact int and bool. You
> can't guarantee the finite time for cycle() and repeat() either since they
> can emit values of arbitrary types, with arbitrary __eq__.


We're not trying to guarantee finite execution time in general, we're just
making it more likely that either Ctrl-C works, or else you don't get stuck
in an infinite loop in the first place.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 17 October 2017 at 19:19, Serhiy Storchaka <storch...@gmail.com> wrote:

> 17.10.17 09:42, Nick Coghlan пише:
>
>> On 17 October 2017 at 16:32, Nick Coghlan <ncogh...@gmail.com > ncogh...@gmail.com>> wrote:
>>
>> So this sounds like a reasonable API UX improvement to me, but you'd
>> need to ensure that you don't inadvertently change the external
>> behaviour of *successful* containment tests.
>>
>>
>> I should also note that there's another option here beyond just returning
>> "False": it would also be reasonable to raise an exception like
>> "RuntimeError('Attempted negative containment check on infinite iterator')".
>>
>
> What about other operations with infinite iterators? min(count()),
> max(count()), all(count(1))? Do you want to implement special cases for all
> of them?


No, as folks expect those to iterate without the opportunity to break out,
and are hence more careful with them when infinite iterators are part of
their application. We also don't have any existing protocols we could use
to intercept them, even if we decided we *did* want to do so.

The distinction I see with "x in y" is:

1. It's pretty easy to write "for x in y in y" when you really meant to
write "for x in y", and if "y" is an infinite iterator, the "y in y" part
will become an unbreakable infinite loop when executed instead of the
breakable one you intended (especially annoying if it means you have to
discard and restart a REPL session due to it, and that's exactly where that
kind of typo is going to be easiest to make)
2. Containment testing already has a dedicated protocol so containers can
implement optimised containment tests, which means it's also trivial for an
infinite iterator to intercept and explicitly disallow containment checks
if it chooses to do so

So the problem is more likely to be encountered due to "x in y" appearing
in both the containment test syntax and as part of the iteration syntax,
*and* it's straightforward to do something about it because the
__contains__ hook already exists. Those two points together are enough for
me to say "Sure, it makes sense to replace the current behaviour with
something more user friendly".

If either of them was false, then I'd say "No, that's not worth the hassle
of changing anything".

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 17 October 2017 at 17:44, Steven D'Aprano <st...@pearwood.info> wrote:

> On Tue, Oct 17, 2017 at 04:42:35PM +1000, Nick Coghlan wrote:
>
> > I should also note that there's another option here beyond just returning
> > "False": it would also be reasonable to raise an exception like
> > "RuntimeError('Attempted negative containment check on infinite
> iterator')".
>
> I don't think that works, even if we limit discussion to just
> itertools.count() rather than arbitrary iterators. Obviously we
> cannot wait until the entire infinite iterator is checked (that
> might take longer than is acceptible...) but if you only check a
> *finite* number before giving up, you lead to false-negatives:
>
> # say we only check 100 values before raising
> 0 in itertools.count(1)  # correctly raises
> 101 in itertools.count(1)  # wrongly raises
>

Nobody suggested that, as it's obviously wrong. This discussion is solely
about infinite iterators that have closed form containment tests, either
because they're computed (itertools.count()), or because they're based on
an underlying finite sequence of values (cycle(), repeat()).


> If we do a computed membership test, then why raise at all? We quickly
> know whether or not the value is in the sequence, so there's no error to
> report.
>

Because we should probably always be raising for these particular
containment checks, and it's safe to start doing so in the negative case,
since that's currently a guaranteed infinite loop.

And unlike a "while True" loop (which has many real world applications),
none of these implicit infinite loops allow for any kind of useful work on
each iteration, they just end up in a tight loop deep inside the
interpreter internals, doing absolutely nothing. They won't even check for
signals or release the GIL, so you'll need to ask the operating system to
clobber the entire process to break out of it - Ctrl-C will be ignored.

I'd also have no major objection to deprecating containment tests on these
iterators entirely, but that doesn't offer the same kind of UX benefit that
replacing an infinite loop with an immediate exception does, so I think the
two questions should be considered separately.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 17 October 2017 at 16:32, Nick Coghlan <ncogh...@gmail.com> wrote:

> So this sounds like a reasonable API UX improvement to me, but you'd need
> to ensure that you don't inadvertently change the external behaviour of
> *successful* containment tests.
>

I should also note that there's another option here beyond just returning
"False": it would also be reasonable to raise an exception like
"RuntimeError('Attempted negative containment check on infinite iterator')".

That way currently working code would be semantically unchanged, but code
that otherwise results in an infinite loop would turn into an immediate
exception instead.

The rationale for this approach would be "What you are trying to do doesn't
really make sense, so we're going to complain about it, rather than just
giving you an answer".

The rationale against the error is that "If this item is present, advance
past it, otherwise don't do anything" would be an at least arguably
reasonable operation to request.

Whether "x in itr" is a reasonable *spelling* of that operation would then
be a different question that still favoured the "raise an exception"
approach.

Cheers,
NIck.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Membership of infinite iterators

2017-10-17 Thread Nick Coghlan
On 16 October 2017 at 11:12, Jason Campbell <j_campbe...@hotmail.com> wrote:

> I recently came across a bug where checking negative membership
> (__contains__ returns False) of an infinite iterator will freeze the
> program.
>
> It may seem a bit obvious, but you can check membership in range for
> example without iterating over the entire range.
>
As Terry noted, this is due to a semantic difference between range (compact
representation of a tuple of integers) and arbitrary iterators.

However, if we can avoid seemingly innocent code triggering an infinite
loop, that's probably a good thing.

> `int(1e100) in range(int(1e101))` on my machine takes about 1.5us
> `int(1e7) in itertools.count()` on my machine takes about 250ms (and gets
> worse quite quickly).
>
> Any membership test on the infinite iterators that is negative will freeze
> the program as stated earlier, which is odd to me.
>
The other relevant behavioural difference is that even a successful
membership test will consume the iterator up to that point.

> itertools.count can use the same math as range
>
+1, with the caveat that a successful containment test should still advance
the iterator to the point immediately after the requested element, just as
it does today (if people don't want that behaviour, they should be defining
a suitable finite range instead).

> itertools.cycle could use membership from the underlying iterable
>
Sort of - you'll still need to iterate through the underlying iterator at
least once in order to see all of the candidate elements. However, the
containment test could still be defined as running through the full cycle
at most once, such that you end up either at the point immediately after
the item or else back where you started (if the item wasn't found).

> itertools.repeat is even easier, just compare to the repeatable element
>
+1

So this sounds like a reasonable API UX improvement to me, but you'd need
to ensure that you don't inadvertently change the external behaviour of
*successful* containment tests.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-16 Thread Nick Coghlan
On 16 October 2017 at 21:08, Juancarlo Añez <apal...@gmail.com> wrote:

>
> Interestingly, thinking about the problem in terms of exception handling
>> flow reminded me of the fact that having a generator-iterator yield while
>> inside a with statement or try/except block is already considered an
>> anti-pattern in many situations, precisely because it means that any
>> exceptions that get thrown in (including GeneratorExit) will be intercepted
>> when that may not be what the author really intended.
>>
>>
> It all works fine now:
>
> https://github.com/neogeny/TatSu/blob/master/tatsu/contexts.py
>
>
> So, I have a strong requirement: whatever is decided on this PEP...
>
> Please don't break it? (or make it illegal)
>

The "anti-pattern in many situations" qualifier was there because there are
cases where it's explicitly expected to work, and isn't an anti-pattern at
all (e.g. when the generator is decorated with contextlib.contextmanager,
or when you're using a context manager to hold open an external resource
like a file until the generator is closed).

So this wasn't intended as an argument for changing anything - rather, it's
about my changing my perspective on how beneficial it would be to have
generators default to maintaining their own distinct logical context (which
then becomes an argument for *not* changing anything).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-15 Thread Nick Coghlan
On 15 October 2017 at 20:45, Paul Moore <p.f.mo...@gmail.com> wrote:

> On 15 October 2017 at 06:43, Nick Coghlan <ncogh...@gmail.com> wrote:
>


> > # Generator form
> > def _results_gen(data):
> > for item in data:
> > with adjusted_context():
> > yield calculate_result(item)
> >
> > results = _results_gen(data)
> >
> > Today, while these two forms look like they *should* be comparable,
> they're
> > not especially close to being semantically equivalent, as there's no
> > mechanism that allows for implicit context reversion at the yield point
> in
> > the generator form.
>
> I'll have to take your word for this, as I can't think of an actual
> example that follows the pattern of your abstract description, for
> which I can immediately see the difference.
>

Interestingly, thinking about the problem in terms of exception handling
flow reminded me of the fact that having a generator-iterator yield while
inside a with statement or try/except block is already considered an
anti-pattern in many situations, precisely because it means that any
exceptions that get thrown in (including GeneratorExit) will be intercepted
when that may not be what the author really intended.

Accordingly, the canonical
guaranteed-to-be-consistent-with-the-previous-behaviour iterator ->
generator transformation already involves the use of a temporary variable
to move the yield outside any exception handling constructs and ensure that
the exception handling only covers the code that it was originally written
to cover:

def _results_gen(data):
for item in data:
with adjusted_context():
result_for_item = calculate_result(item)
yield result_for_item

results = _results_gen(data)

The exception handling expectations with coroutines are different, since an
"await cr" expression explicitly indicates that any exceptions "cr" fails
to handle *will* propagate back through to where the await appears, just as
"f()" indicates that unhandled exceptions in "f" will be seen by the
current frame.

And even if as a new API context variables were to be defined in a
yield-tolerant way, a lot of existing context managers still wouldn't be
"yield safe", since they may be manipulating thread local or process global
state, rather than context variables or a particular object instance.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Why not picoseconds?

2017-10-15 Thread Nick Coghlan
On 16 October 2017 at 04:28, Victor Stinner <victor.stin...@gmail.com>
wrote:

> I proposed to use nanoseconds because UNIX has 1 ns resolution in
> timespec, the most recent API, and Windows has 100 ns.
>
> Using picoseconds would confuse users who may expect sub-nanosecond
> resolution, whereas no OS support them currently.
>
> Moreover, nanoseconds as int already landed in os.stat and os.utime.
>

And this precedent also makes sense to me as the rationale for using an
"_ns" API suffix within the existing module rather than introducing a new
module.


> Last but not least, I already strugle in pytime.c to prevent integer
> overflow with 1 ns resolution. It can quickly become much more complex if
> there is no native C int type supporting a range large enough to more 1
> picosecond resolution usable. I really like using int64_t for _PyTime_t,
> it's well supported, very easy to use (ex: "t = t2 - t1"). 64-bit int
> supports year after 2200 for delta since 1970.
>

Hopefully by the time we decide it's worth worrying about picoseconds in
"regular" code, compiler support for decimal128 will be sufficiently
ubiquitous that we'll be able to rely on that as our 3rd generation time
representation (where the first gen is seconds as a 64 bit binary float and
the second gen is nanoseconds as a 64 bit integer).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-15 Thread Nick Coghlan
On 15 October 2017 at 15:49, Nathaniel Smith <n...@pobox.com> wrote:

> It's not like this is a new and weird concept in Python either -- e.g.
> when you raise an exception, the relevant 'except' block is determined
> based on where the 'raise' happens (the runtime stack), not where the
> 'raise' was written:
>
> try:
> def foo():
> raise RuntimeError
> except RuntimeError:
> print("this is not going to execute, because Python doesn't work that
> way")
> foo()
>

Exactly - this is a better formulation of what I was trying to get at when
I said that we want the semantics of context variables in synchronous code
to reliably align with the semantics of the synchronous call stack as it
appears in an exception traceback.

Attempting a pithy summary of PEP 550's related semantics for use in
explanations to folks that don't care about all the fine details:

The currently active execution context aligns with the expected flow of
exception handling for any exceptions raised in the code being executed.

And with a bit more detail:

* If the code in question will see the exceptions your code raises, then
your code will also be able to see the context variables that it defined or
set
* By default, this relationship is symmetrical, such that if your code will
see the exceptions that other code raises as a regular Python exception,
then you will also see the context changes that that code makes.
* However, APIs and language features that enable concurrent code execution
within a single operating system level thread (like event loops, coroutines
and generators) may break that symmetry to avoid context variable
management conflicts between concurrently executing code. This is the key
behavioural difference between context variables (which enable this by
design) and thread local variables (which don't).
* Pretty much everything else in the PEP 550 API design is a lower level
performance optimisation detail to make management of this dynamic state
sharing efficient in event-driven code

Even PEP 550's proposal for how yield would work aligns with that "the
currently active execution context is the inverse of how exceptions will
flow" notion: the idea there is that if a context manager's __exit__ method
wouldn't see an exception raised by a piece of code, then that piece of
code also shouldn't be able to see any context variable changes made by
that context manager's __enter__ method (since the changes may not get
reverted correctly on failure in that case).

Exceptions raised in a for loop body *don't* typically get thrown back into
the body of the generator-iterator, so generator-iterators' context
variable changes should be reverted at their yield points.

By contrast, exceptions raised in a with statement body *do* get thrown
back into the body of a generator decorated with contextlib.contextmanager,
so those context variable changes should *not* be reverted at yield points,
and instead left for __exit__ to handle.

Similarly, coroutines are in the exception handling path for the other
coroutines they call (just like regular functions), so those coroutines
should share an execution context rather than each having their own.

All of that leads to it being specifically APIs that already need to do
special things to account for exception handling flows within a single
thread (e.g. asyncio.gather, asyncio.ensure_future,
contextlib.contextmanager) that are likely to have to put some thought into
how they will impact the active execution context.

Code for which the existing language level exception handling semantics
already work just fine should then also be able to rely on the default
execution context management semantics.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-14 Thread Nick Coghlan
On 15 October 2017 at 15:05, Guido van Rossum <gu...@python.org> wrote:

> I would like to reboot this discussion (again). It feels to me we're
> getting farther and farther from solving any of the problems we might solve.
>
> I think we need to give up on doing anything about generators; the use
> cases point in too many conflicting directions. So we should keep the
> semantics there, and if you don't want your numeric or decimal context to
> leak out of a generator, don't put `yield` inside `with`. (Yury and Stefan
> have both remarked that this is not a problem in practice, given that there
> are no bug reports or StackOverflow questions about this topic.)
>

Let me have another go at building up the PEP 550 generator argument from
first principles.

The behaviour that PEP 550 says *shouldn't* change is the semantic
equivalence of the following code:

# Iterator form
class ResultsIterator:
def __init__(self, data):
self._itr = iter(data)
def __next__(self):
return calculate_result(next(self._itr))

results = _ResultsIterator(data)

# Generator form
def _results_gen(data):
for item in data:
yield calculate_result(item)

results = _results_gen(data)

This *had* been non-controversial until recently, and I still don't
understand why folks suddenly decided we should bring it into question by
proposing that generators should start implicitly capturing state at
creation time just because it's technically possible for them to do so (yes
we can implicitly change the way all generators work, but no, we can't
implicitly change the way all *iterators* work).

The behaviour that PEP 550 thinks *should* change is for the following code
to become roughly semantically equivalent, given the constraint that the
context manager involved either doesn't manipulate any shared state at all
(already supported), or else only manipulates context variables (the new
part that PEP 550 adds):

# Iterator form
class ResultsIterator:
def __init__(self, data):
self._itr = iter(data)
def __next__(self):
with adjusted_context():
return calculate_result(next(self._itr))

results = _ResultsIterator(data)

# Generator form
def _results_gen(data):
for item in data:
with adjusted_context():
yield calculate_result(item)

results = _results_gen(data)

Today, while these two forms look like they *should* be comparable, they're
not especially close to being semantically equivalent, as there's no
mechanism that allows for implicit context reversion at the yield point in
the generator form.

While I think PEP 550 would still be usable without fixing this
discrepancy, I'd be thoroughly disappointed if the only reason we decided
not to do it was because we couldn't clearly articulate the difference in
reasoning between:

* "Generators currently have no way to reasonably express the equivalent of
having a context-dependent return statement inside a with statement in a
__next__ method implementation, so let's define one" (aka "context variable
changes shouldn't leak out of generators, as that will make them *more*
like explicit iterator __next__ methods"); and
* "Generator functions should otherwise continue to be unsurprising
syntactic sugar for objects that implement the regular iterator protocol"
(aka "generators shouldn't implicitly capture their creation context, as
that would make them *less* like explicit iterator __init__ methods").

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-14 Thread Nick Coghlan
On 15 October 2017 at 14:53, M.-A. Lemburg <m...@egenix.com> wrote:

> On 15.10.2017 06:39, Nick Coghlan wrote:
> > On 15 October 2017 at 05:47, Paul Moore <p.f.mo...@gmail.com
> > <mailto:p.f.mo...@gmail.com>> wrote:
> >
> > On 14 October 2017 at 17:50, Nick Coghlan <ncogh...@gmail.com
> > <mailto:ncogh...@gmail.com>> wrote:
> > > If you capture the context eagerly, then there are fewer
> opportunities to
> > > get materially different values from "data = list(iterable)" and
> "data =
> > > iter(context_capturing_iterable)".
> > >
> > > While that's a valid intent for folks to want to be able to
> express, I
> > > personally think it would be more clearly requested via an
> expression like
> > > "data = iter_in_context(iterable)" rather than having it be
> implicit in the
> > > way generators work (especially since having eager context capture
> be
> > > generator-only behaviour would create an odd discrepancy between
> generators
> > > and other iterators like those in itertools).
> >
> > OK. I understand the point here - but I'm not sure I see the
> practical
> > use case for iter_in_context. When would something like that be used?
> >
> >
> > Suppose you have some existing code that looks like this:
> >
> > results = [calculate_result(a, b) for a, b in data]
> >
> > If calculate_result is context dependent in some way (e.g. a & b might
> > be decimal values), then eager evaluation of "calculate_result(a, b)"
> > will use the context that's in effect on this line for every result.
> >
> > Now, suppose you want to change the code to use lazy evaluation, so that
> > you don't need to bother calculating any results you don't actually use:
> >
> > results = (calculate_result(a, b) for a, b in data)
> >
> > In a PEP 550 world, this refactoring now has a side-effect that goes
> > beyond simply delaying the calculation: since "calculate_result(a, b)"
> > is no longer executed immediately, it will default to using whatever
> > execution context is in effect when it actually does get executed, *not*
> > the one that's in effect on this line.
> >
> > A context capturing helper for iterators would let you decide whether or
> > not that's what you actually wanted by instead writing:
> >
> > results = iter_in_context(calculate_result(a, b) for a, b in data)
> >
> > Here, "iter_in_context" would indicate explicitly to the reader that
> > whenever another item is taken from this iterator, the execution context
> > is going to be temporarily reset back to the way it was on this line.
> > And since it would be a protocol based iterator-in-iterator-out
> > function, you could wrap it around *any* iterator, not just
> > generator-iterator objects.
>
> I have a hard time seeing the advantage of having a default
> where the context at the time of execution is dependent on
> where it happens rather than where it's defined.
>

The underlying rationale is that the generator form should continue to be
as close as we can reasonably make it to being pure syntactic sugar for the
iterator form:

class ResultsIterator:
def __init__(self, data):
self._itr = iter(data)
def __next__(self):
return calculate_result(next(self._itr))

results = _ResultsIterator(data)

The logical context adjustments in PEP 550 then serve to make using a with
statement around a yield expression in a generator closer in meaning to
using one around a return statement in a __next__ method implementation.


> IMO, the default should be to use the context where the line
> was defined in the code, since that matches the intuitive
> way of writing and defining code.
>

This would introduce a major behavioural discrepancy between generators and
iterators.


> The behavior of also deferring the context to time of
> execution should be the non-standard form to not break
> this intuition, otherwise debugging will be a pain and
> writing fully working code would be really hard in the
> face of changing contexts (e.g. say decimal rounding
> changes in different parts of the code).
>

No, it really wouldn't, since "the execution context is the context that's
active when the code is executed" is relatively easy to understand based
entirely on the way functions, methods, and other forms of delayed
execution work (including iterators).

"The execution context is the context that's active when the code is
executed, *unless* the code is in a generator, in which case, it's the
context that was active when the generator-iterator was instantiated" is
harder to follow.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-14 Thread Nick Coghlan
On 15 October 2017 at 05:47, Paul Moore <p.f.mo...@gmail.com> wrote:

> On 14 October 2017 at 17:50, Nick Coghlan <ncogh...@gmail.com> wrote:
> > If you capture the context eagerly, then there are fewer opportunities to
> > get materially different values from "data = list(iterable)" and "data =
> > iter(context_capturing_iterable)".
> >
> > While that's a valid intent for folks to want to be able to express, I
> > personally think it would be more clearly requested via an expression
> like
> > "data = iter_in_context(iterable)" rather than having it be implicit in
> the
> > way generators work (especially since having eager context capture be
> > generator-only behaviour would create an odd discrepancy between
> generators
> > and other iterators like those in itertools).
>
> OK. I understand the point here - but I'm not sure I see the practical
> use case for iter_in_context. When would something like that be used?
>

Suppose you have some existing code that looks like this:

results = [calculate_result(a, b) for a, b in data]

If calculate_result is context dependent in some way (e.g. a & b might be
decimal values), then eager evaluation of "calculate_result(a, b)" will use
the context that's in effect on this line for every result.

Now, suppose you want to change the code to use lazy evaluation, so that
you don't need to bother calculating any results you don't actually use:

results = (calculate_result(a, b) for a, b in data)

In a PEP 550 world, this refactoring now has a side-effect that goes beyond
simply delaying the calculation: since "calculate_result(a, b)" is no
longer executed immediately, it will default to using whatever execution
context is in effect when it actually does get executed, *not* the one
that's in effect on this line.

A context capturing helper for iterators would let you decide whether or
not that's what you actually wanted by instead writing:

results = iter_in_context(calculate_result(a, b) for a, b in data)

Here, "iter_in_context" would indicate explicitly to the reader that
whenever another item is taken from this iterator, the execution context is
going to be temporarily reset back to the way it was on this line. And
since it would be a protocol based iterator-in-iterator-out function, you
could wrap it around *any* iterator, not just generator-iterator objects.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-14 Thread Nick Coghlan
f
> "micro tasks" are something non-experts might need to write, but not
> realise they are straying into deep waters. But I've no way of knowing
> how likely that is.
>

A micro-task is just a fancier name for  the "iter_in_context" idea above
(save the current context when the iterator is created, switch back to that
context every time you're asked for a new value).


> One final point, this is all pretty deeply intertwined with the
> comprehensibility of async as a whole. At the moment, as I said
> before, async is a specialised area that's largely only used in
> projects that centre around it. In the same way that Twisted is its
> own realm - people write network applications without Twisted, or they
> write them using Twisted. Nobody uses Twisted in the middle of some
> normal non-async application like pip to handle grabbing a webpage.
> I'm uncertain whether the intent is for the core async features to
> follow this model, or whether we'd expect in the longer term for
> "utility adoption" of async to happen (tactical use of async for
> something like web crawling or collecting subprocess output in a
> largely non-async app). If that *does* happen, then async needs to be
> much more widely understandable - maintenance programmers who have
> never used async will start encountering it in corners of their
> non-async applications, or find it used under the hood in libraries
> that they use. This discussion is a good example of the implications
> of that - async quirks leaking out into the "normal" world (decimal
> contexts) and as a result the async experts needing to be able to
> communicate their concerns and issues to non-experts.
>

Aye, this is why I'd like the semantics of context variables to be almost
indistinguishable from those of thread local variables for synchronous code
(aside from avoiding context changes leaking out of generator-iterators
when they yield from inside a with statement).

PEP 550 currently does a good job of ensuring that, but we'd break that
near equivalence if generators were to implicitly capture their creation
context.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Add time.time_ns(): system clock with nanosecond resolution

2017-10-14 Thread Nick Coghlan
On 14 October 2017 at 18:21, Antoine Pitrou <solip...@pitrou.net> wrote:

> On Sat, 14 Oct 2017 10:49:11 +0300
> Serhiy Storchaka <storch...@gmail.com>
> wrote:
> > I don't like the idea of adding a parallel set of functions.
> >
> > In the list of alternatives in PEP 410 there is no an idea about fixed
> > precision float type with nanoseconds precision. It can be implemented
> > internally as a 64-bit integer, but provide all methods required for
> > float-compatible number. It would be simpler and faster than general
> > Decimal.
>
> I agree a parallel set of functions is not ideal, but I think a parallel
> set of functions is still more appropriate than a new number type
> specific to the time module.
>
> Also, if you change existing functions to return a new type, you risk
> breaking compatibility even if you are very careful about designing the
> new type.
>

Might it make more sense to have a parallel *module* that works with a
different base data type rather than parallel functions within the existing
API?

That is, if folks wanted to switch to 64-bit nanosecond time, they would
use:

* time_ns.time()
* time_ns.monotonic()
* time_ns.perf_counter()
* time_ns.clock_gettime()
* time_ns.clock_settime()

The idea here would be akin to the fact we have both math and cmath as
modules, where the common APIs conceptually implement the same algorithms,
they just work with a different numeric type (floats vs complex numbers).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Add a module itertools.recipes

2017-10-14 Thread Nick Coghlan
On 14 October 2017 at 16:06, Antoine Rozo <antoine.r...@gmail.com> wrote:

> I am not searching for an external library (as I pointed, there are some
> on PyPI like iterutils or more-itertools).
> My point was that recipes are documented in itertools module, but not
> implemented in standard library, and it would be useful to have them
> available.
>

Not providing the recipes as an importable API is a deliberate design
decision, as what folks often need is code that is
similar-to-but-not-exactly-the-same-as the code in the recipe. If they've
copied the code into their own utility library, then that's not a problem -
they can just edit their version to have the exact semantics they need.

Individual recipes may occasionally get promoted to be part of the module
API, but that only happens on a case by case basis, and requires a
compelling justification for the change ("It's sometimes useful" isn't
compelling enough - we know it's sometimes useful, that's why it's listed
as an example recipe).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-14 Thread Nick Coghlan
On 14 October 2017 at 08:44, Steve Dower <steve.do...@python.org> wrote:

>
> It's not possible to special case __aenter__ and __aexit__ reliably
>> (supporting wrappers, decorators, and possible side effects).
>>
>
> Why not? Can you not add a decorator that sets a flag on the code object
> that means "do not create a new context when called", and then it doesn't
> matter where the call comes from - these functions will always read and
> write to the caller's context. That seems generally useful anyway, and then
> you just say that __aenter__ and __aexit__ are special and always have that
> flag set.
>

One example where giving function names implicit semantic significance
becomes problematic:

async def start_transaction(self):
...

async def end_transaction(self, *exc_details):
...

__aenter__ = start_transaction
__aexit__ = end_transaction

There *are* ways around that (e.g. type.__new__ implicitly wraps
__init_subclass__ with classmethod since it makes no sense as a regular
instance method), but then you still run into problems like this:

async def __aenter__(self):
return await self.start_transaction()

async def __aexit__(self, *exc_details):
return await self.end_transaction(*exc_details)

If coroutines were isolated from their parents by default, then the above
method implementations would be broken, even though the exact same
invocation pattern works fine for synchronous function calls.

To try and bring this back to synchronous examples that folks may find more
intuitive, I figure it's worth framing the question this way: do we want
people to reason about context variables like the active context is
implicitly linked to the synchronous call stack, or do we want to encourage
them to learn to reason about them more like they're a new kind of closure?

The reason I ask that is because there are three "interesting" times in the
life of a coroutine or generator:

- definition time (when the def statement runs - this determines the
lexical closure)
- instance creation time (when the generator-iterator or coroutine is
instantiated)
- execution time (when the frame actually starts running - this determines
the runtime call stack)

For synchronous functions, instance creation time and execution time are
intrinsically linked, since the execution frame is allocated and executed
directly as part of calling the function.

For asynchronous operations, there's more of a question, since actual
execution is deferred until you call await or next() - the original
synchronous call to the factory function instantiates an object, it doesn't
actually *do* anything.

The current position of PEP 550 (which I agree with) is that context
variables should default to being closely associated with the active call
stack (regardless of whether those calls are regular synchronous ones, or
asynchronous ones with await), as this keeps the synchronous and
asynchronous semantics of context variables as close to each other as we
can feasibly make them.

When implicit isolation takes place, it's either to keep concurrently
active logical call stacks isolated from each other (the event loop case),
and else to keep context changes from implicitly leaking *up* a stack (the
generator case), not to keep context changes from propagating *down* a call
stack.

When we do want to prevent downward propagation for some reason, then
that's what "run_in_execution_context" is for: deliberate creation of a new
concurrently active call stack (similar to running something in another
thread to isolate the synchronous call stack).

Don't get me wrong, I'm not opposed to the idea of making it trivial to
define "micro tasks" (iterables that perform a context switch to a
specified execution context every time they retrieve a new value) that can
provide easy execution context isolation without an event loop to manage
it, I just think that would be more appropriate as a wrapper API that can
be placed around any iterable, rather than being baked in as an intrinsic
property of generators.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-13 Thread Nick Coghlan
On 13 October 2017 at 10:56, Guido van Rossum <gu...@python.org> wrote:

> I'm out of energy to debate every point (Steve said it well -- that
> decimal/generator example is too contrived), but I found one nit in Nick's
> email that I wish to correct.
>
> On Wed, Oct 11, 2017 at 1:28 AM, Nick Coghlan <ncogh...@gmail.com> wrote:
>>
>> As a less-contrived example, consider context managers implemented as
>> generators.
>>
>> We want those to run with the execution context that's active when
>> they're used in a with statement, not the one that's active when they're
>> created (the fact that generator-based context managers can only be used
>> once mitigates the risk of creation time context capture causing problems,
>> but the implications would still be weird enough to be worth avoiding).
>>
>
> Here I think we're in agreement about the desired semantics, but IMO all
> this requires is some special casing for @contextlib.contextmanager. To me
> this is the exception, not the rule -- in most *other* places I would want
> the yield to switch away from the caller's context.
>
>
>> For native coroutines, we want them to run with the execution context
>> that's active when they're awaited or when they're prepared for submission
>> to an event loop, not the one that's active when they're created.
>>
>
> This caught my eye as wrong. Considering that asyncio's tasks (as well as
> curio's and trio's) *are* native coroutines, we want complete isolation
> between the context active when `await` is called and the context active
> inside the `async def` function.
>

The rationale for this behaviour *does* arise from a refactoring argument:

   async def original_async_function():
with some_context():
do_some_setup()
raw_data = await some_operation()
data = do_some_postprocessing(raw_data)

Refactored:

   async def async_helper_function():
do_some_setup()
raw_data = await some_operation()
return do_some_postprocessing(raw_data)

   async def refactored_async_function():
with some_context():
data = await async_helper_function()

However, considering that coroutines are almost always instantiated at the
point where they're awaited, I do concede that creation time context
capture would likely also work out OK for the coroutine case, which would
leave contextlib.contextmanager as the only special case (and it would turn
off both creation-time context capture *and* context isolation).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-11 Thread Nick Coghlan
On 11 October 2017 at 02:52, Guido van Rossum <gu...@python.org> wrote:

> I think we really need to do more soul-searching before we decide that a
> much more complex semantics and implementation is worth it to maintain
> backwards compatibility for leaking in via next().
>

As a less-contrived example, consider context managers implemented as
generators.

We want those to run with the execution context that's active when they're
used in a with statement, not the one that's active when they're created
(the fact that generator-based context managers can only be used once
mitigates the risk of creation time context capture causing problems, but
the implications would still be weird enough to be worth avoiding).

For native coroutines, we want them to run with the execution context
that's active when they're awaited or when they're prepared for submission
to an event loop, not the one that's active when they're created.

For generators-as-coroutines, we want them to be like their native
coroutine counterparts: run with the execution context that's active when
they're passed to "yield from" or prepared for submission to an event loop.

It's only for generators-as-iterators that the question of what behaviour
we want even really arises, as it's less clear cut whether we'd be better
off overall if they behaved more like an eagerly populated container (and
hence always ran with the execution context that's active when they're
created), or more like the way they do now (where retrieval of the next
value from a generator is treated like any other method call).

That combination of use cases across context managers, native coroutines,
top level event loop tasks, and generator-based coroutines mean we already
need to support both execution models regardless, so the choice of default
behaviour for generator-iterators won't make much difference to the overall
complexity of the PEP.

However, having generator-iterators default to *not* capturing their
creation context makes them more consistent with the other lazy evaluation
constructs, and also makes the default ContextVar semantics more consistent
with thread local storage semantics.

The flipside of that argument would be:

* the choice doesn't matter if there aren't any context changes between
creation & use
* having generators capture their context by default may ease future
migrations from eager container creation to generators in cases that
involve context-dependent calculations
* decorators clearing the implicitly captured context from the
generator-iterator when appropriate is simpler than writing a custom
iterator wrapper to handle the capturing

I just don't find that counterargument compelling when we have specific use
cases that definitely benefit from the proposed default behaviour
(contextlib.contextmanager, asyncio.coroutine), but no concrete use cases
for the proposed alternative that couldn't be addressed by a combination of
map(), functools.partial(), and contextvars.run_in_execution_context().

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-10 Thread Nick Coghlan
On 10 October 2017 at 22:51, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> ​I see no reason why these two should be equivalent.
>

There is no "should" about it: it's a brute fact that the two forms *are*
currently equivalent for lazy iterators (including generators), and both
different from the form that uses eager evaluation of the values before the
context change.

Where should enters into the picture is by way of PEP 550 saying that they
should *remain* equivalent because we don't have an adequately compelling
justification for changing the runtime semantics.

That is, given the following code:

itr = make_iter()
with decimal.localcontext() as ctx:
ctc.prex = 30
for i in itr:
  pass

Right now, today, in 3.6. the calculations in the iterator will use the
modified decimal context, *not* the context that applied when the iterator
was created. If you want to ensure that isn't the case, you have to force
eager evaluation before the context change.

What PEP 550 is proposing is that, by default, *nothing changes*: the lazy
iteration in the above will continue to use the updated decimal context by
default.

However, people *will* gain a new option for avoiding that: instead of
forcing eager evaluation, they'll be able to capture the creation context
instead, and switching back to that each time the iterator needs to
calculate a new value.

If PEP 555 proposes that we should instead make lazy iteration match eager
evaluation semantics by *default*, then that's going to be a much harder
case to make because it's a gratuitous compatibility break - code that
currently works one way will suddenly start doing something different, and
end users will have difficulty getting it to behave the same way on 3.7 as
it does on earlier versions.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-10 Thread Nick Coghlan
On 10 October 2017 at 22:34, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> Really, it was my mistake to ever make you think that
> context_var.assign(42).__enter__() can be compared to .set(42) in PEP
> 550. I'll say it once more: PEP 555 context arguments have no equivalent of
> the PEP-550 .set(..).
>

Then your alternate PEP can't work, since it won't be useful to extension
modules.

Context managers are merely syntactic sugar for try/finally statements, so
you can't wave your hands and say a context manager is the only supported
API: you *have* to break the semantics down and explain what the
try/finally equivalent looks like.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-10 Thread Nick Coghlan
On 10 October 2017 at 01:24, Guido van Rossum <gu...@python.org> wrote:

> On Sun, Oct 8, 2017 at 11:46 PM, Nick Coghlan <ncogh...@gmail.com> wrote:
>
>> On 8 October 2017 at 08:40, Koos Zevenhoven <k7ho...@gmail.com> wrote:
>>
>>> ​​I do remember Yury mentioning that the first draft of PEP 550 captured
>>> something when the generator function was called. I think I started reading
>>> the discussions after that had already been removed, so I don't know
>>> exactly what it was. But I doubt that it was *exactly* the above, because
>>> PEP 550 uses set and get operations instead of "assignment contexts" like
>>> PEP 555 (this one) does. ​​
>>>
>>
>> We didn't forget it, we just don't think it's very useful.
>>
>
> I'm not sure I agree on the usefulness. Certainly a lot of the complexity
> of PEP 550 exists just to cater to Nathaniel's desire to influence what a
> generator sees via the context of the send()/next() call. I'm still not
> sure that's worth it. In 550 v1 there's no need for chained lookups.
>

The compatibility concern is that we want developers of existing libraries
to be able to transparently switch from using thread local storage to
context local storage, and the way thread locals interact with generators
means that decimal (et al) currently use the thread local state at the time
when next() is called, *not* when the generator is created.

I like Yury's example for this, which is that the following two examples
are currently semantically equivalent, and we want to preserve that
equivalence:

with decimal.localcontext() as ctx:
ctc.prex = 30
for i in gen():
   pass

g = gen()
with decimal.localcontext() as ctx:
ctc.prex = 30
for i in g:
  pass

The easiest way to maintain that equivalence is to say that even though
preventing state changes leaking *out* of generators is considered a
desirable change, we see preventing them leaking *in* as a gratuitous
backwards compatibility break.

This does mean that *neither* form is semantically equivalent to eager
extraction of the generator values before the decimal context is changed,
but that's the status quo, and we don't have a compelling justification for
changing it.

If folks subsequently decide that they *do* want "capture on creation" or
"capture on first iteration" semantics for their generators, those are easy
enough to add as wrappers on top of the initial thread-local-compatible
base by using the same building blocks as are being added to help event
loops manage context snapshots for coroutine execution.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP draft: context variables

2017-10-09 Thread Nick Coghlan
On 8 October 2017 at 08:40, Koos Zevenhoven <k7ho...@gmail.com> wrote:

> On Sun, Oct 8, 2017 at 12:16 AM, Nathaniel Smith <n...@pobox.com> wrote:
>
>> On Oct 7, 2017 12:20, "Koos Zevenhoven" <k7ho...@gmail.com> wrote:
>>
>>
>> ​Unfortunately, we actually need a third kind of generator semantics,
>> something like this:
>>
>> @​contextvars.caller_context
>> def genfunc():
>> assert cvar.value is the_value
>> yield
>> assert cvar.value is the_value
>>
>> with cvar.assign(the_value):
>> gen = genfunc()
>>
>> next(gen)
>>
>> with cvar.assign(1234567890):
>> try:
>> next(gen)
>> except StopIteration:
>> pass
>>
>> Nick, Yury and I (and Nathaniel, Guido, Jim, ...?) somehow just narrowly
>> missed the reasons for this in discussions related to PEP 550. Perhaps
>> because we had mostly been looking at it from an async angle.
>>
>>
>> That's certainly a semantics that one can write down (and it's what the
>> very first version of PEP 550 did),
>>
>
> ​​I do remember Yury mentioning that the first draft of PEP 550 captured
> something when the generator function was called. I think I started reading
> the discussions after that had already been removed, so I don't know
> exactly what it was. But I doubt that it was *exactly* the above, because
> PEP 550 uses set and get operations instead of "assignment contexts" like
> PEP 555 (this one) does. ​​
>

We didn't forget it, we just don't think it's very useful. However, if you
really want those semantics under PEP 550, you can do something like this:

def use_creation_context(g):
@functools.wraps(g)
def make_generator_wrapper(*args, **kwds):
gi = g(*args, **kwds)
return _GeneratorWithCapturedEC(gi)
return make_generator_wrapper

class _GeneratorWithCapturedEC:
def __init__(self, gi):
self._gi = gi
self._ec = contextvars.get_execution_context()
def __next__(self):
return self.send(None)
def send(self, value):
return contextvars.run_with_execution_context(self.ec,
self._gi.send, value)
def throw(self, *exc_details):
return contextvars.run_with_execution_context(self.ec,
self._gi.throw, *exc_details)
def close(self):
return self.throw(GeneratorExit)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Add pop_callback to deque signature

2017-10-03 Thread Nick Coghlan
On 4 October 2017 at 04:24, Chris Barker <chris.bar...@noaa.gov> wrote:
> [Antoine]
>> The problem as
>> I understand it is that you need a Windows machine (or VM) together with
>> the required set of compilers, and have to take the time to run the
>> builds.
>
> Yup — still the case. Also with Mac and OS-X. Distributing a package with a
> compiled component is still a lot more work.

The broad availability & popularity of AppVeyor's free tier is another
relevant change compared to a few years ago, and
https://github.com/joerick/cibuildwheel is designed to work with that
to help projects automate their artifact builds without need to
maintain their own cross-platform build infrastructure.

So yeah, we're definitely to a point where adding new data structures
to the standard library, or new features to existing data structures,
is mainly going to be driven by standard library use cases that
benefit from them, rather than "binary dependencies are still too hard
to publish & manage". (For example, __missing__ made defaultdict easy
to implement).

For deque specifically, I like Steven D'Aprano's suggestion of a
"__dropped__" or "__discard__" subclassing API that makes it
straightforward to change the way that queue overruns are handled
(especially if raising an exception from the new subclass method can
prevent the collection modification entirely - that way you could
readily change the deque semantics in a subclass such that if the
queue fills up, submitters start getting errors instead of silently
discarding older messages, allowing backpressure to be more easily
propagated through a system of queues).

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Changes to the existing optimization levels

2017-10-03 Thread Nick Coghlan
On 4 October 2017 at 01:42, Diana Clarke <diana.joan.cla...@gmail.com> wrote:
> On Sun, Oct 1, 2017 at 6:19 AM, Antoine Pitrou <solip...@pitrou.net> wrote:
>> Well, this is not really a bitfield, but a bitfield plus some irregular
>> hardcoded values.  Therefore I don't think it brings much in the way of
>> discoverability / understandability.
>>
>> That said, perhaps it makes implementation easier on the C side...
>
> I think I'm coming to the same conclusion: using bitwise operations
> for the optimization levels seems to just boil down to a more cryptic
> version of the simple "level 3" solution, with public-facing impacts
> to the pycache and existing interfaces etc that I don't think are
> worth it in this case.
>
> My only other thought at the moment, would be to use the existing -X
> option to achieve something similar to what I did with the new -N
> option, but then just quickly map that back to an integer under the
> hood. That is, "-X opt-nodebug -X opt-noassert" would just become
> "level 3" internally so that the various interfaces wouldn't have to
> change.

Sorry, I don't think I was entirely clear as to what my suggestion actually was:

* Switch to your suggested "set-of-strings" API at the Python level,
with the Python level integer interface retained only for backwards
compatibility
* Keep the current integer-based *C* optimization API, but redefine
the way that value is interpreted, rather than passing Python sets
around

The Python APIs would then convert the Python level sets to the
bitfield representation almost immediately for internal use, but you
wouldn't need to mess about with the bitfield yourself when calling
the Python APIs.

The difference I see relates to the fact that in Python:

* sets of strings are easier to work with than integer bitfields
* adding a new keyword-only argument to existing APIs is straightforward

While in C:

* integer bitfields are easier to work with than Python sets of Python strings
* supporting a new argument would mean defining a whole new parallel set of APIs

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


<    1   2   3   4   5   6   >