Re: [Python-ideas] Syntax to import modules before running command from the command line

2018-01-09 Thread Ivan Pozdeev via Python-ideas

On 10.01.2018 0:54, Barry Warsaw wrote:

Steve Barnes wrote:

Currently invoking `python -c "some;separated;set of commands;"` will,
if you need to use any library functions, require one or more import
somelib; sections in the execution string. This results in rather
complex "one liners".

On the other hand `python -m somelib` will load somelib and attempt to
execute its `__main__()` or give an error if there isn't one.

What I would like to suggest is a mechanism to pre-load libraries before
evaluating the -c option as this would allow the use of code from
libraries that don't have a `__main__` function, or those that do but it
doesn't do what you want.

It would be really cool if you could somehow write a file with a bunch
of commands in it, and then get Python to execute those commands.  Then
it could still be a one line invocation, but you could do much more
complex things, including import a bunch of modules before executing
some code.  I'm not sure what such a file would look like but here's a
strawman:

IPython's `run -i' does that.


```
import os
import sys
import somelib

path = somelib.get_path()
parent = os.path.dirname(path)
print(parent)

sys.exit(0 if os.path.isdir(parent) else 1)
```

Then you could run it like so:

$ python3 myscript.py

That seems like a nice, compact, one line invocation, but cI don't know,
it probably needs some fleshing out.  It's just a crazy idea, and
there's probably not enough time to implement this for Python 3.7.
Maybe for Python 3.8.

time-machine-winking-ly y'rs,
-Barry


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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] Support WHATWG versions of legacy encodings

2018-01-09 Thread Ivan Pozdeev via Python-ideas
First of all, many thanks for such a excellently writen letter. It was a 
real pleasure to read.


On 10.01.2018 0:15, Rob Speer wrote:
Hi! I joined this list because I'm interested in filling a gap in 
Python's standard library, relating to text encodings.


There is an encoding with no name of its own. It's supported by every 
current web browser and standardized by WHATWG. It's so prevalent that 
if you ask a Web browser to decode "iso-8859-1" or "windows-1252", you 
will get this encoding _instead_. It is probably the second or third 
most common text encoding in the world. And Python doesn't quite 
support it.


You can see the character table for this encoding at:
https://encoding.spec.whatwg.org/index-windows-1252.txt

For the sake of discussion, let's call this encoding "web-1252". 
WHATWG calls it "windows-1252", but notice that it's subtly different 
from Python's "windows-1252" encoding. Python's windows-1252 has bytes 
that are undefined:


>>> b'\x90'.decode('windows-1252')
UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 
0: character maps to 


In web-1252, the bytes that are undefined according to windows-1252 
map to the control characters in those positions in iso-8859-1 -- that 
is, the Unicode codepoints with the same number as the byte. In 
web-1252, b'\x90' would decode as '\u0090'.
According to https://en.wikipedia.org/wiki/Windows-1252 , Windows does 
the same:


    "According to the information on Microsoft's and the Unicode 
Consortium's websites, positions 81, 8D, 8F, 90, and 9D are unused; 
however, the Windows API |MultiByteToWideChar 
| 
maps these to the corresponding C1 control codes 
."


And in ISO-8859-1, the same handling is done for unused code points even 
by the standard ( https://en.wikipedia.org/wiki/ISO/IEC_8859-1 ) :


    "*ISO-8859-1* is the IANA 
 
preferred name for this standard when supplemented with the C0 and C1 
control codes  
from ISO/IEC 6429 "


And what would you think -- these "C1 control codes" are also the 
corresponding Unicode points! ( 
https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block) 
 )


Since Windows is pretty much the reference implementation for 
"windows-" encodings, it even makes sense to alter the existing 
encodings rather than add new ones.




This may seem like a silly encoding that encourages doing horrible 
things with text. That's pretty much the case. But there's a reason 
every Web browser implements it:


- It's compatible with windows-1252
- Any sequence of bytes can be round-tripped through it without losing 
information


It's not just this one encoding. WHATWG's encoding standard 
(https://encoding.spec.whatwg.org/) contains modified versions of 
windows-1250 through windows-1258 and windows-874.


Support for these encodings matters to me, in part, because I maintain 
a Unicode data-cleaning library, "ftfy". One thing it does is to 
detect and undo encoding/decoding errors that cause mojibake, as long 
as they're detectible and reversible. Looking at real-world examples 
of text that has been damaged by mojibake, it's clear that lots of 
text is transferred through what I'm calling the "web-1252" encoding, 
in a way that's incompatible with Python's "windows-1252".


In order to be able to work with and fix this kind of text, ftfy 
registers new codecs -- and I implemented this even before I knew that 
they were standardized in Web browsers. When ftfy is imported, you can 
decode text as "sloppy-windows-1252" (the name I chose for this 
encoding), for example.


ftfy can tell people a sequence of steps that they can use in the 
future to fix text that's like the text they provided. Very often, 
these steps require the sloppy-windows-1252 or sloppy-windows-1251 
encoding, which means the steps only work with ftfy imported, even for 
people who are not using the features of ftfy.


Support for these encodings also seems highly relevant to people who 
use Python for web scraping, as it would be desirable to maximize 
compatibility with what a Web browser would do.


This really seems like it belongs in the standard library instead of 
being an incidental feature of my library. I know that code in the 
standard library has "one foot in the grave". I _want_ these legacy 
encodings to have one foot in the grave. But some of them are 
extremely common, and Python code should be able to deal with them.


Adding these encodings to Python would be straightforward to 
implement. Does this require a PEP, a pull request, or further discussion?



___
Python-ideas mailing list

Re: [Python-ideas] Allow to compile debug extension against releasePython in Windows

2018-01-09 Thread Ivan Pozdeev via Python-ideas

On 09.01.2018 23:31, Barry Scott wrote:
I not a user of distutils or setuptools but some googling seems to say 
that

the build command has a --debug to do what you want. If that does not
work it would seem like you could ask the setuptools maintainers how to
do the reason thing of a debug build.

I just wrote, in 
https://mail.python.org/pipermail/python-ideas/2018-January/048579.html 
, that --debug is not sufficient, and that the problematic logic is in 
distutils, not setuptools.


--
Regards,
Ivan

___
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 to compile debug extension against releasePython in Windows

2018-01-09 Thread Ivan Pozdeev via Python-ideas

On 09.01.2018 21:35, Ivan Pozdeev via Python-ideas wrote:


On 08.01.2018 0:11, Steve Dower wrote:


It’s not a good idea. You end up with two different C runtimes in 
memory that cannot communicate, and many things will not work properly.


If you compile your debug build extension with the non-debug CRT (/MD 
rather than /MDd) you will lose asserts, but otherwise it will work 
fine and the quoted code picks the release lib.



Distutils' designers seem to have thought differently.
Whether the extension is linked against pythonxx_d.lib is governed by 
the --debug switch to the `build' command rather than the type of the 
running Python. Compiler optimization flags and /MD(d) are inserted 
according to it, too.


As a consequence,
* I cannot install an extension into debug Python at all 'cuz 
`bdist_*' and `install' commands don't support --debug and invoke 
`debug' internally without it.

I meant "invoke `build' internally without it." , sorry.

This kafkaesque "you cannot do this because you cannot do this" is 
taking its toll on me...
* Neither can I compile an extension for release Python without 
optimizations.


I'm at a loss here. Either I'm missing something, or with the current 
build system, it's impossible to debug extensions!


Or if you like, when you install Python 3.5 or later there are 
advanced options to install debug symbols and binaries. You can use a 
proper debug build against the debug binaries (python_d.exe).


Cheers,

Steve

Top-posted from my Windows phone

*From: *Ivan Pozdeev via Python-ideas <mailto:python-ideas@python.org>
*Sent: *Saturday, December 30, 2017 13:01
*To: *python-ideas@python.org <mailto:python-ideas@python.org>
*Subject: *[Python-ideas] Allow to compile debug extension against 
releasePython in Windows


The Windows version of pyconfig.h has the following construct:

    if defined(_DEBUG)

   pragma comment(lib,"python37_d.lib")

    elif defined(Py_LIMITED_API)

   pragma comment(lib,"python3.lib")

    else

   pragma comment(lib,"python37.lib")

    endif /* _DEBUG */

which fails the compilation of a debug version of an extension. Making

debugging it... difficult.

Perhaps we could define some other constant?

I'm not sure whether such compilation is a good idea in general, so

asking here at first.

--

Regards,

Ivan

___

Python-ideas mailing list

Python-ideas@python.org

https://mail.python.org/mailman/listinfo/python-ideas

Code of Conduct: http://python.org/psf/codeofconduct/



--
Regards,
Ivan


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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 to compile debug extension against releasePython in Windows

2018-01-09 Thread Ivan Pozdeev via Python-ideas

On 08.01.2018 0:11, Steve Dower wrote:


It’s not a good idea. You end up with two different C runtimes in 
memory that cannot communicate, and many things will not work properly.


If you compile your debug build extension with the non-debug CRT (/MD 
rather than /MDd) you will lose asserts, but otherwise it will work 
fine and the quoted code picks the release lib.



Distutils' designers seem to have thought differently.
Whether the extension is linked against pythonxx_d.lib is governed by 
the --debug switch to the `build' command rather than the type of the 
running Python. Compiler optimization flags are inserted according to 
it, too.


As a consequence,
* I cannot install an extension into debug Python at all 'cuz `bdist_*' 
and `install' commands don't support --debug and invoke `debug' 
internally without it.
* Neither can I compile an extension for release Python without 
optimizations.


I'm at a loss here. Either I'm missing something, or with the current 
build system, it's impossible to debug extensions!


Or if you like, when you install Python 3.5 or later there are 
advanced options to install debug symbols and binaries. You can use a 
proper debug build against the debug binaries (python_d.exe).


Cheers,

Steve

Top-posted from my Windows phone

*From: *Ivan Pozdeev via Python-ideas <mailto:python-ideas@python.org>
*Sent: *Saturday, December 30, 2017 13:01
*To: *python-ideas@python.org <mailto:python-ideas@python.org>
*Subject: *[Python-ideas] Allow to compile debug extension against 
releasePython in Windows


The Windows version of pyconfig.h has the following construct:

    if defined(_DEBUG)

   pragma comment(lib,"python37_d.lib")

    elif defined(Py_LIMITED_API)

   pragma comment(lib,"python3.lib")

    else

   pragma comment(lib,"python37.lib")

    endif /* _DEBUG */

which fails the compilation of a debug version of an extension. Making

debugging it... difficult.

Perhaps we could define some other constant?

I'm not sure whether such compilation is a good idea in general, so

asking here at first.

--

Regards,

Ivan

___

Python-ideas mailing list

Python-ideas@python.org

https://mail.python.org/mailman/listinfo/python-ideas

Code of Conduct: http://python.org/psf/codeofconduct/



--
Regards,
Ivan

___
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] [Python-Dev] subprocess not escaping "^" on Windows

2018-01-07 Thread Ivan Pozdeev via Python-ideas

On 07.01.2018 22:32, Christian Tismer wrote:

Hi Chris,

On 07.01.18 18:18, Chris Angelico wrote:

Redirecting this part of the conversation to python-ideas.

On Mon, Jan 8, 2018 at 3:17 AM, Christian Tismer  wrote:

As a side note: In most cases where shell=True is found, people
seem to need evaluation of the PATH variable. To my understanding,


from subprocess import call
call(("ls",))

works in Linux, but (with dir) not in Windows. But that is misleading
because "dir" is a builtin command but "ls" is not. The same holds for
"del" (Windows) and "rm" (Linux).

That's exactly what shell=True is for - if you want a shell feature,
you use the shell. What exactly would emulate_shell do? Would it
simply do a $PATH or %PATH% search, but otherwise function as
shell=False? Would it process redirection? Would it handle
interpolations? I think not, from your description:


Perhaps it would be a good thing to emulate the builtin programs
in python by some shell=True replacement (emulate_shell=True?)
to match the normal user expectations without using the shell?

but it becomes difficult to draw the line. For instance, with
emulate_shell=True, what would you do with all the sh/bash built-ins:

https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html
https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html

I'm thinking especially of the commands where bash has its own
handling of something that could otherwise be found in $PATH, like
pwd, time, and echo, but shells can do a lot of other things too.

When do you actually want to execute a shell built-in from Python but
without using the shell itself? You give the example of ls/dir, but if
that ever comes up in real-world code, I'd toss it out and recommend a
cross-platform os.listdir or equivalent. There are plenty of times
I've wanted a really quick way to redirect a standard stream from
Python, but that isn't part of what you're recommending. Can you give
a real-world example that would be improved by this?

I know this was just a side note in your original, but I'd like to
hear more about what would make it useful.


No, I cannot. I just thought of a way to keep users from using
"shell=True". I *think* they do it after they experience that
"del" for instance is not found. They conclude "ah, I need the
shell", which is not true.
Even putting aside the fact this is pure conjecture, the kind of people 
who make decisions like this will find a zillion more ways to shoot 
themselves in the foot. They don't need a cleaner syntax, they need to 
learn the basics of programming in a high-level language to understand 
how it's different from programming in the shell. In particular, why 
spawning a subprocess for something covered by a library function is a 
bad idea.


So whatever you come up with, the effect should be that people
no longer use the shell. THATs what I want, after bad experience with
non-escaped "^" in a regex, that caused some really weird result.



___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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] Allow to compile debug extension against release Python in Windows

2017-12-29 Thread Ivan Pozdeev via Python-ideas

The Windows version of pyconfig.h has the following construct:

    if defined(_DEBUG)
   pragma comment(lib,"python37_d.lib")
    elif defined(Py_LIMITED_API)
   pragma comment(lib,"python3.lib")
    else
   pragma comment(lib,"python37.lib")
    endif /* _DEBUG */

which fails the compilation of a debug version of an extension. Making 
debugging it... difficult.


Perhaps we could define some other constant?

I'm not sure whether such compilation is a good idea in general, so 
asking here at first.


--
Regards,
Ivan

___
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] Repr of lambda

2017-12-17 Thread Ivan Pozdeev via Python-ideas

On 17.12.2017 22:20, Serhiy Storchaka wrote:
Currently repr of doesn't contain much of information besides that it 
is a lambda.


>>> lambda x: x**2
 at 0x7f3479b74488>

All lambdas have the same repr, different only by unreadable 
hexadecimal address.


What if include the signature and the expression of the lambda in its 
repr?


>>> lambda x: x**2



It's the same for named functions:

    In [1]: def ditto(a): return a

    In [2]: ditto
    Out[2]: 

Are you intending to do the same for them?
This would return an old feature of Python 0.9.1 
(https://twitter.com/dabeaz/status/934835068043956224).


Repr of function could contain just the signature.



But there is a problem with default values. Their reprs can be very 
long, especially in the following case with mutable default value:


def foo(x, _cache={}):
    try:
    return _cache[x]
    except KeyError:
    pass
    _cache[x] = y = expensive_calculation(x)
    return y

Maybe the placeholder should be always used instead of default values.

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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 dict with the attribute access capability

2017-12-01 Thread Ivan Pozdeev via Python-ideas



On 01.12.2017 1:19, Greg Ewing wrote:

Ivan Pozdeev via Python-ideas wrote:
I needed to hold an external function reference in an object instance 
(if I assigned it to an attribute, it was converted into an instance 
method).


No, that only happens to functions stored in *class* attributes,
not instance attributes.

>>> class A:
...    pass
...
>>> a = A()
>>>
>>> def f():
...    print("I'm just a function")
...
>>> a.x = f
>>> a.x()
I'm just a function

Well, yes, that was a singleton class, so I kept data in the class 
object. Now I can simplify the code by only keeping the instance 
reference in the class, thank you. (Without knowing this, that bore no 
visible benefits.)


--
Regards,
Ivan

___
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] [Python-Dev] What's the status of PEP 505: None-aware operators?

2017-11-30 Thread Ivan Pozdeev via Python-ideas

On 29.11.2017 9:08, Steven D'Aprano wrote:

On Tue, Nov 28, 2017 at 12:31:06PM -0800, Raymond Hettinger wrote:

I also cc python-dev to see if anybody here is strongly in favor or against 
this inclusion.

Put me down for a strong -1.  The proposal would occasionally save a
few keystokes but comes at the expense of giving Python a more Perlish
look and a more arcane feel.

I think that's an unfair characterisation of the benefits of the PEP.
It's not just "a few keystrokes".

Ironically, the equivalent in Perl is // which Python has used for
truncating division since version 2.4 or so. So if we're in danger of
looking "Perlish", that ship has sailed a long time ago.

Perl is hardly the only language with null-coalescing operators -- we
might better describe ?? as being familiar to C#, PHP, Swift and Dart.
That's two mature, well-known languages and two up-and-coming languages.

My experience with these operators in C# says:
* They do save "more than a few keystrokes". Even more importantly, they 
allow to avoid double evaluation or the need for a temporary variable 
workaround that are inherent in " if  else "
    * (An alternative solution for the latter problem would be an 
assignment expression, another regularly rejected proposal.)

* They make it temptingly easy and implicit to ignore errors.
* They are alien to Python's standard semantics on search failure which 
is to raise an exception rather than return None


[...]

 timeout ?? local_timeout ?? global_timeout

As opposed to the status quo:

 timeout if timeout is not None else (local_timeout if local_timeout is not 
None else global_timeout)

Or shorter, but even harder to understand:

 (global_timeout if local_timeout is None else local_timeout) if timeout is 
None else timeout

I'd much prefer to teach the version with ?? -- it has a simple
explanation: "the first of the three given values which isn't None". The
?? itself needs to be memorized, but that's no different from any other
operator. The first time I saw ** I was perplexed and couldn't imagine
what it meaned.

Here ?? doesn't merely save a few keystrokes, it significantly reduces
the length and complexity of the expression and entirely cuts out the
duplication of names.

If you can teach

 timeout or local_timeout or global_timeout

then you ought to be able to teach ??, as it is simpler: it only
compares to None, and avoids needing to explain or justify Python's
truthiness model.



 'foo' in (None ?? ['foo', 'bar'])

If you can understand

 'foo' in (False or ['foo', 'bar'])

then surely you can understand the version with ??.



 requested_quantity ?? default_quantity * price

Again:

 (default_quantity if requested_quantity is None else requested_quantity) * 
price


I'd much prefer to read, write and teach the version with ?? over the
status quo.




--
Regards,
Ivan

___
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 dict with the attribute access capability

2017-11-30 Thread Ivan Pozdeev via Python-ideas

I use argparse.Namespace whenever I need this.

In reply to Chris Barker's concern of "is this code or is this data", 
the last time I used it is when I needed to hold an external function 
reference in an object instance (if I assigned it to an attribute, it 
was converted into an instance method). It just didn't feel right to 
invoke it via a container lookup.


A telling name for the object also clears doubts about what it's 
supposed to hold.


On 29.11.2017 11:52, Serhiy Storchaka wrote:
In 3.7 I have removed an old-deprecated plistlib.Dict. [1] Actually it 
already was deprecated when the plistlib module was added to the 
regular stdlib in Python 2.6.


This is a dict subclass which allows to access items as attributes.

d = plistlib.Dict()
d['a'] = 1
assert d.a == 1
d.b = 2
assert d['b'] == 2

Raymond noticed that that capability seemed nice to have.

What do you think about reviving this type as general purpose type in 
collections or types? Perhaps it can be convenient for working with 
JSON, plists, configuration files, databases and in other cases that 
need a dict with string keys.


If reintroduce it, there are open questions.

1. The name of the type.

2. The location of the type. collections or types? Or other variants?

3. How it will collaborate with OrderedDict, defaultdict, etc?

4. Should it be a dict subclass, or a mixin, or a proxy? Or add 
several types?



[1] https://bugs.python.org/issue29196

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 28.11.2017 20:23, Ethan Furman wrote


On 11/28/2017 08:03 AM, Ivan Pozdeev via Python-ideas wrote:

On 28.11.2017 16:36, Nick Coghlan wrote:



   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


The bulk of any processing in assert (or ensure()) should be the 
actual check -- if that fails, only state information should be 
included in the exception as anything more complicated runs the risk 
of also being wrong as the code is now in a failed state.  In other 
words, the "error-related arguments" will often be extremely cheap 
compared to the test itself.


My experience is the contrary. The check is usually trivial -- a type 
check or comparison. While a useful error message contains problem 
details, so it incorporates string formatting from a variable or two or 
expressions thereof, like "expected , got <type(var)>".

--
~Ethan~
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 28.11.2017 16:36, Nick Coghlan wrote:


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
Another benefit of a statement vs function is only evaluating the 
error-related arguments when there's an error

- 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 :)



--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 28.11.2017 10:22, Elazar wrote:

Just a note : in typechecked code (such as mypy's source code) assert 
is used to guide the checker:


assert isinstance(x, CallableType)
return x.args  # checker knows it's valid

So the assert becomes a kind of type annotation. The runtime check 
helps during tests, but is not that important - failure will be caught 
relatively soon. And I believe that the ability to remove the check at 
runtime is important, since isinstance calls have non-negligible 
impact on performance in mypy.

(but other contributors here can correct me on this).

This results in two different interfaces. In normal mode, it enforces 
types while in -O, accepts anything that passes the duck test.


Elazar


בתאריך יום ג׳, 28 בנוב׳ 2017, 09:12, מאת Ivan Pozdeev via Python-ideas 
‏<python-ideas@python.org <mailto:python-ideas@python.org>>:


On 28.11.2017 8:59, Steven D'Aprano wrote:
> On Tue, Nov 28, 2017 at 07:35:45AM +0300, Ivan Pozdeev via
    Python-ideas wrote:
>
>> Actually, the way I'm using them,
>>
>>      assert condition, "error message", type
>>
>> would probably be the most expressive way.
> I disagree that is expressive -- I call it *misleading*. I see
something
> which looks like an assertion (that is, a checked comment, a
contract, a
> check on an internal piece of logic etc) but it is actually
being used
> as a test.
>
>
>> I can do anything in any Turing-complete language without any
changes to
>> the language. That's no reason to never change anything, is it.
> "We can change this" is not a reason to change this. There needs
to be a
> *good* reason to change, and you have given no good reasons for this
> change.
>
>
>> The rationale basically is:
>> * As it was intended, the statement has no practical use --
basically a
>> rudiment, due to disappear eventually
> Nonsense. I make extensive use of assert as a way of checking
> assertions, and I will fight tooth and nail against any proposal to
> either remove it or to misuse it for public input tests instead of
> assertions.
I invite you to show me a single use case for those "assertions"
because
after ~20 years of experience in coding (that included fairly large
projects), I've yet to see one.

Any, every check that you make at debug time either
* belongs in production as well (all the more because it's harder to
diagnose there), or
* belongs in a test -- something coded independently from the program
(if your code as a whole cannot be trusted, how any specific part
of it
can?), or
* isn't needed at all because a fault will inevitably surface
somewhere
down the line (as some exception or an incorrect result that a
test will
catch).

Finally, I've got much experience using existing code outside its
original use cases, where the original author's assumptions may no
longer hold but the specific logic can be gauded to produce the
desired
result. Coding these assumptions in would undermine that goal.

So, I see "debug assertions" as either intentionally compromizing
correctness for performance (a direct opposite of Python's design
principles), or as an inferiour, faulty, half-measure rudiment from
times when CI wasn't a thing (thus not something that should be taught
and promoted as a best practice any longer).
>
>> * It can instead be reused as syntax sugar to cover a very
common use case
> There is no need for such syntactic sugar. It would be harmful
> to use assert for something which is not an assertion.
>
>
>

--
Regards,
Ivan

___
Python-ideas mailing list
Python-ideas@python.org <mailto:Python-ideas@python.org>
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/



--
Regards,
Ivan

___
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-27 Thread Ivan Pozdeev via Python-ideas

On 28.11.2017 8:59, Steven D'Aprano wrote:

On Tue, Nov 28, 2017 at 07:35:45AM +0300, Ivan Pozdeev via Python-ideas wrote:


Actually, the way I'm using them,

     assert condition, "error message", type

would probably be the most expressive way.

I disagree that is expressive -- I call it *misleading*. I see something
which looks like an assertion (that is, a checked comment, a contract, a
check on an internal piece of logic etc) but it is actually being used
as a test.



I can do anything in any Turing-complete language without any changes to
the language. That's no reason to never change anything, is it.

"We can change this" is not a reason to change this. There needs to be a
*good* reason to change, and you have given no good reasons for this
change.



The rationale basically is:
* As it was intended, the statement has no practical use -- basically a
rudiment, due to disappear eventually

Nonsense. I make extensive use of assert as a way of checking
assertions, and I will fight tooth and nail against any proposal to
either remove it or to misuse it for public input tests instead of
assertions.
I invite you to show me a single use case for those "assertions" because 
after ~20 years of experience in coding (that included fairly large 
projects), I've yet to see one.


Any, every check that you make at debug time either
* belongs in production as well (all the more because it's harder to 
diagnose there), or
* belongs in a test -- something coded independently from the program 
(if your code as a whole cannot be trusted, how any specific part of it 
can?), or
* isn't needed at all because a fault will inevitably surface somewhere 
down the line (as some exception or an incorrect result that a test will 
catch).


Finally, I've got much experience using existing code outside its 
original use cases, where the original author's assumptions may no 
longer hold but the specific logic can be gauded to produce the desired 
result. Coding these assumptions in would undermine that goal.


So, I see "debug assertions" as either intentionally compromizing 
correctness for performance (a direct opposite of Python's design 
principles), or as an inferiour, faulty, half-measure rudiment from 
times when CI wasn't a thing (thus not something that should be taught 
and promoted as a best practice any longer).



* It can instead be reused as syntax sugar to cover a very common use case

There is no need for such syntactic sugar. It would be harmful
to use assert for something which is not an assertion.





--
Regards,
Ivan

___
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-27 Thread Ivan Pozdeev via Python-ideas

On 28.11.2017 6:34, Ned Batchelder wrote:



You are proposing:

    assert condition, type, value

Not specifically this, that's just an example.

Actually, the way I'm using them,

    assert condition, "error message", type

would probably be the most expressive way.


Why not just use Python as it is now, with this:?

It's the most expressive way the language provides to write that logic.
With Python's design focus on promoting expressive, readable and 
intuitive syntax, that's enough of a reason.


    if not condition: raise type(value)

I don't see a reason to change the assert statement. You can do what 
you need without the change.
I can do anything in any Turing-complete language without any changes to 
the language. That's no reason to never change anything, is it.


The rationale basically is:
* As it was intended, the statement has no practical use -- basically a 
rudiment, due to disappear eventually

* It can instead be reused as syntax sugar to cover a very common use case

--
Regards,
Ivan

___
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-27 Thread Ivan Pozdeev via Python-ideas

On 28.11.2017 5:19, Chris Angelico wrote:


Actually, Python does have a way of disabling assertions (the -O
flag), so they should be treated the same way they are in C.
Assertions should not be used as shorthands for "if cond: raise Exc"
in the general case.
I'm claiming, and provided evidence, that there are no use cases for 
this in Python, so no-one (of any significance) will suffer when the 
disabling is cut out.
In any case, we will probably do it with a __future__ statement for a 
transitional period.


--
Regards,
Ivan

___
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] Repurpose `assert' into a general-purpose check

2017-11-27 Thread Ivan Pozdeev via Python-ideas
The `assert' statment was created the same as in previous languages like 
C/C++: a check to only do in debug mode, when you can't yet trust your 
code to manage and pass around internal data correctly. Examples are 
array bounds and object state integrity constraints.


Unlike C, Python does the aforementioned checks all the time, i.e. it's 
effectively always in "debug mode". Furthermore, validation checks are 
an extremily common use case.


I have been using assert in my in-house code for input validation for a 
long time, the only thing preventing me from doing the same in public 
code is the fact that it only raises AssertionError's while library code 
is expected to raise TypeError or ValueError on invalid input.


The last drop that incited me to do this proposition was 
https://stackoverflow.com/questions/2142202/what-are-acceptable-use-cases-for-pythons-assert-statement 
where none of the _seven_ answer authors (beside me) managed to make a 
_single realistic use case_ for `assert' as a debug-only check.


---

So, I'm hereby proposing to:

* make `assert' stay in optimized mode
* change its syntax to raise other types of exceptions

E.g.: "assert condition, type, value" or "assert condition, type, 
exception_constructor_argument(s)" to maintain backward compatibility.


--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 07.11.2017 23:38, Chris Barker wrote:
with ensurepip, having pip no installed in a python is getting less 
common, so maybe this isn't needed anymore, but
pip is problematic in environments that have their own package manager 
(i.e. anything but bare Windows) because it doesn't honor its 
conventions (e.g. if it's a non-default Python installation, all its 
packages must use versioned or otherwise custom names for executable 
modules - see e.g. 
https://stackoverflow.com/questions/40718770/pytest-running-with-another-version-of-python 
for an illustration). That's why it's not installed by default in 
environments where that's a significant problem.


--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 07.11.2017 18:34, Stephan Houben wrote:

One (smaller) suggestion on the PATH situation on Windows:

I noticed that Visual C++ Build Tools installs a number of  "Command 
prompts"
under its Start menu item, each of which starts a cmd.exe with 
appropriate PATH

set to the appropriate compiler (32/64 bits or ARM cross-compiler), and
assorted environment variables set to the appropriate include/library 
directories.


Could we do something similar for Python?

I.e., Install under the "Python 3.6" start menu an additional
"Python command prompt", which will
start cmd.exe with an appropriate PATH so that python and pip
run without further prefix.

That way, the installer still doesn't need to mess with global PATH 
and you can

easily have multiple versions of Python, each with their own
"Python command prompt" submenu.

At least for Windows users this would simplify the situation a bit.

Stephan

This suggestion is no different from environemnt activation scripts of 
anaconda/pyenv/virtualenv -- without the other benefits of virtualenv.


IPython solves this by creating version-specific executables (even in 
Windows). I see no reason why executables of Python proper cannot do the 
same. In fact, the reason why Windows version went Py instead of this 
seems to rather be to solve a completely different problem -- the 
filetype association (when running a script via ShellExecute, it 
autodetects which Python version to invoke).




2017-11-06 23:53 GMT+01:00 Ivan Pozdeev via Python-ideas 
<python-ideas@python.org <mailto:python-ideas@python.org>>:


On 07.11.2017 1:48, Chris Barker wrote:

On Mon, Nov 6, 2017 at 9:52 AM, Michel Desmoulin
<desmoulinmic...@gmail.com <mailto:desmoulinmic...@gmail.com>> wrote:

I know and you still:

- have to use py -m on windows, python3 linux, python in
virtualenv...


can't you use python3 -m pip install .

everywhere?

You can't. Windows versions don't create versioned executables.
Got bitten with this myself.


...Maybe they should?
(This is python-ideas, after all ;-) )

-- 
Regards,

Ivan


___
Python-ideas mailing list
Python-ideas@python.org <mailto:Python-ideas@python.org>
https://mail.python.org/mailman/listinfo/python-ideas
<https://mail.python.org/mailman/listinfo/python-ideas>
Code of Conduct: http://python.org/psf/codeofconduct/
<http://python.org/psf/codeofconduct/>




--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 07.11.2017 16:11, Paul Moore wrote:

It is, but like any such approach (Cygwin is similar, in principle if
not in execution) that makes one OS "look like" another, whether it's
appropriate is very dependent on circumstances. Training potential
Windows developers in a bash/Ubuntu style environment leaves them at a
disadvantage when they need to develop for actual Windows
environments.
Moreover, one of the key selling points of Python is that it can 
interface with anything and everything found in any environment!
Rather than e.g. conjuring up a closed circle with own replacements for 
everything than forces everyone into the lowest common denominator like 
Java does.


*That's another key reason why I use & suggest using an installation 
"native" to the system whenever possible.*
It's as close to "being an integral part of the environment rather than 
rejecting it and creating an inferior copy" philosophy as one can get.


--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 07.11.2017 1:48, Chris Barker wrote:
On Mon, Nov 6, 2017 at 9:52 AM, Michel Desmoulin 
> wrote:


I know and you still:

- have to use py -m on windows, python3 linux, python in virtualenv...


can't you use python3 -m pip install .

everywhere?
You can't. Windows versions don't create versioned executables. Got 
bitten with this myself.



...Maybe they should?
(This is python-ideas, after all ;-) )

--
Regards,
Ivan

___
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 Ivan Pozdeev via Python-ideas

On 06.11.2017 9:47, Michel Desmoulin wrote:

Hello,

Today I'm going to give a training in Python again.

And again it will go the same way.

On Mac I will have to make people install python, then tell them to use
pip3.

On Windows, I will have to warn them about checking the "add python
executable to system path" (that one of them will ALWAYS miss anyway).
Then tell them to use py -3.x -m pip because some of them will have
several versions of Python installed.

Then on linux, I will tell them to install python-pip and python-venv
and use python3 -m pip.

I'll talk about --user, but commands won't be usable on some machine
where the Scripts or bin dir is not in the system path.

Then I will make them create a virtualenv so that they can avoid messing
with their system python and finally can just use "pip install" like in
most tutorials on the Web.

And eventually I'll talk about pipenv and conda. The first one so they
don't have to think about activating the virtualenv everytime, or pip
freeze, or create the venv, or add it to gitignore, etc. The second
because anaconda is very popular on windows.

There is no way a beginner is going to get any that by themselves
without a lot of time and pain. They will read some tutorial on the web
and struggle to make sens of what pip is and why "pip install" doesn't
work and why "python sucks".

I don't see anything particularly bogging here.
It's always like this when you have multiple versions of the same 
software on the system. There's only one PATH, after all.


Heck, *the mere fact that Python allows to work like this is already a 
huge leap forward.* **Doing this cross-platform with exactly the same 
steps is something few could believe was even possible a couple of years 
ago!**


With most other software packages, it's either not possible at all (and 
an installer for a different version of a package requires uninstalling 
the existing version first), or you need to compile everything from 
source with custom --prefix or something -- and deal with dependency 
hell looming over your head when they unexpectedly override some system 
components, or have to specify paths all the time.


This is why system package managers in Linux distributions are such a 
huge help -- as long as you're using the same repository (or a 
closely-knitted group thereof), you're supposed to have a sane 
environment whatever packages you install, with nothing overriding 
anything else.



To simplify things with Python, i do the following:
* use the system's Python whenever possible
* if using something else, only install the one version/environment that 
I'm using day-to-day and add it to PATH (system's if safe & convenient, 
personal otherwise)
* prefer the system's/environment's package manager to pip to install 
3rd-party modules, too, if there is one.


For personal day-to-day use, it's very rarely critical to use precisely 
specific versions of Python and packages.
For commerical use, I'll either mainly use one environment still (the 
one my production or my client has), or have to deal with multiple 
environments anyway, or set a up a dedicated CI server/environment and 
leave its scripts to deal with them.



I think Python is offering an incredible experience for first timer.
However, the whole "where is walpip" shenanigans is not one of them.

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.

Michel

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
Regards,
Ivan

___
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] Python-ideas Digest, Vol 131, Issue 106

2017-10-31 Thread Ivan Pozdeev via Python-ideas

On 31.10.2017 8:37, python-ideas-requ...@python.org wrote:
On Tue, Oct 31, 2017 at 3:50 PM, Ivan Pozdeev via Python-ideas 
<python-ideas@python.org> wrote:

On 30.10.2017 17:32, Guido van Rossum wrote:

This is a key example of a case where code speaks. Can you write an
implementation of how you would want single() to work in Python code?

On Mon, Oct 30, 2017 at 2:49 AM, Ivan Pozdeev via Python-ideas
<python-ideas@python.org  <mailto:python-ideas@python.org>> wrote:

 The initial post on the above link summarizes the suggested
 implementation pretty well.


|defsingle(i): try: ||v =i.next()
|||exceptStopIteration:raiseException('No values')|||try: ||i.next()
||exceptStopIteration: ||returnv||else: ||raiseException('Too many values')|
||printsingle(name forname in('bob','fred')ifname=='bob')||| |

||

raise WhitespaceDamagedException from None

ChrisA


Thunderbird jerked on me big time. It never did anything like this 
before! Switched off Digest mode, individual messages aren't so complicated.


def single(i):
    try:
    v =i.next()
    except StopIteration:
    raise ValueError('No items')
    try:
    i.next()
    except StopIteration:
    return v
    else:
    raise ValueError('More than one item')

print single(name for name in('bob','fred') if name=='bob')

--

Regards,
Ivan

___
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 single() to itertools

2017-10-30 Thread Ivan Pozdeev via Python-ideas

On 30.10.2017 17:32, Guido van Rossum wrote:
This is a key example of a case where code speaks. Can you write an 
implementation of how you would want single() to work in Python code?


On Mon, Oct 30, 2017 at 2:49 AM, Ivan Pozdeev via Python-ideas 
<python-ideas@python.org <mailto:python-ideas@python.org>> wrote:


The initial post on the above link summarizes the suggested
implementation pretty well.


|defsingle(i): try: ||v =i.next() |||exceptStopIteration:raiseException('No 
values')|||try: ||i.next() ||exceptStopIteration: ||returnv||else: 
||raiseException('Too many values')|
||printsingle(name forname in('bob','fred')ifname=='bob')||| |
||

--
Regards,
Ivan

___
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] Add processor generation to wheel metadata

2017-10-30 Thread Ivan Pozdeev via Python-ideas
Generally, packages are compiled for the same processor generation as 
the corresponding Python.
But not always -- e.g. NumPy opted for SSE2 even for Py2 to work around 
some compiler bug

(https://github.com/numpy/numpy/issues/6428).
I was bitten by that at an old machine once and found out that there is 
no way for `pip' to have checked for that.
Besides, performance-oriented packages like the one mentioned could 
probably benefit from newer instructions.


Regarding identifiers:
gcc, cl and clang all have their private directories of generation 
identifiers:

https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/i386-and-x86_002d64-Options.html
https://msdn.microsoft.com/en-us/library/7t5yh4fd.aspx
https://clang.llvm.org/doxygen/Driver_2ToolChains_2Arch_2X86_8cpp_source.html

Linux packages typically use gcc's ones. Clang generally follows in 
gcc's footsteps and accepts cl's IDs, too, as aliases.


So, using the IDs of whatever compiler is used to build the package 
(i.e. most likely the canonical compiler for CPython for that platform) 
looks like the simple(r) way - we can just take the value of the 
"march" argument.



The tricky part is mapping the system's processor to an ID when checking 
compatibility: the logic will have to keep a directory (that's the job 
of `wheel' package maintainers though, I guess).
I also guess that there are cases where there's no such thing as _the_ 
system's processor.


--
Regards,
Ivan

___
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] Add single() to itertools

2017-10-29 Thread Ivan Pozdeev via Python-ideas
The eponymous C#'s LINQ method, I found very useful in the following, 
quite recurring use-case:


I need to get a specific element from a data structure that only 
supports search semantics (i.e. returns a sequence/iterator of results).
For that, I specify very precise search criteria, so only that one item 
is supposed to be found. But I'd rather verify that just in case.


"A data structure that only supports search semantics" is a recurring 
phenomenon due to this:


I make a special-purpose data structure (usually for some 
domain-specific data like task specification or data directory) using a 
combination of existing and/or new containers. Now, these types do not 
enforce all the integrity constraints of my data. And I don't wish to 
construct a special-purpose class, complete with validation procedures, 
and pass records into it one by one etc -- when I can just write an 
initializer, loading all the data at once in a nicely readable 
construct, and call it a day.


So, when querying this structure, I "know" that there should only be one 
item satisfying a certain criteria - if there's more, or less, something 
is wrong with the data.


https://stackoverflow.com/questions/46009985/get-contentcontrol-by-title-or-tag 
is the most recent occasion where I had this use case (that is not 
Python but the concept is language-agnostic).


--
Regards,
Ivan

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/