[Python-ideas] Re: PEP 472 -- Support for indexing with keyword arguments

2020-07-15 Thread Caleb Donovick
I have wanted this and suggested it before for use with typing.

Defining  protocols is obnoxiously verbose for "struct" like data and
keyword
arguments to subscript could help alleviate that.
I often want to write type hint like this:

```
def foo(x: Protocol[id=int, name=str]):
  bar(x)
  baz(x)

def bar(x: Protocol[name=str]): ...

def baz(x: Protocol[id=int]): ...
```

So  I either need to specify more restrictive types than necessary (which
often
is not possible because I reuse my functions), or generate a combinatorial
number of Protocols.  Beyond the obvious annoyances that come with having
to
generate many protocols, simply naming them is cognitively expensive.  I
don't
need to bind an identifier when declaring a Union or specializing a generic
but
if I want to say I have a type with some attribute it MUST be named.


On Fri, Jul 10, 2020 at 10:00 AM Paul Moore  wrote:

> On Fri, 10 Jul 2020 at 17:45, Steven D'Aprano  wrote:
>
> > I must admit I like the look of this, but I don't know what I would use
> > it for.
>
> It feels very much like the sort of "here's some syntax that might
> match someone's mental model of something" that is common in languages
> that focus on allowing users to build their own DSLs¹ (Lua and Groovy
> are two examples of the type of language I'm thinking of, although I
> don't know if either has this particular syntax).
>
> Python typically doesn't encourage DSL-style programming, so this type
> of "syntax looking for a use case" isn't very popular.
>
> Paul
>
> ¹ DSL = Domain Specific Language, in case anyone isn't familiar with the
> term.
> ___
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/HUELPGHPCAIFLUKCQ5G7O2LKQFRRZ6CU/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/Q3LB4F76MPWC33D2KZFNO6PL4XSOSS6V/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Stephen J. Turnbull
Random832 writes:

 > I was asking for the current Unpickler class, which currently has a
 > whitelist hook for loading globals,

Callables are globals in this sense.  So overriding
Unpickler.find_class will allow you to restrict to specified
callables.  It's not clear to me why you would want more fine-grained
control: why not put the argument checking in the object constructor?
In most cases that's probably where it's most useful, anyway, by DRY.

 > to be modified to also have a whitelist hook so that an application
 > can provide a function that looks at a callable and its arguments
 > that the pickle proposes to call, and can choose to either evaluate
 > it, raise an error, or return a substitute value.

I would guess you can already have this by overriding
Unpickler.load_reduce and patching Unpickler.dispatch[REDUCE[0]] to
the new load_reduce.  Is there any other way for a pickle to specify
the code to invoke on data supplied by that pickle?

 > The idea that the pickle format is "inherently unsafe" and cannot
 > be made safe is magical thinking.

I think you're quite wrong.  Pickle format itself is inherently unsafe
because it allows a pickle to specify code to be executed on data that
pickle specifies.  Of course that assumes that the problem code
somehow got into a Python file on your PYTHON_PATH, but pickle format
surely allows that in the absence of a specified threat model that
rules it out.

I'm sure it's true that some particular uses of pickle format can be
safe.  But you need to say what you need the code using pickle to do,
and what threats you need to be safe against.  Note that "pickle
format is unsafe" is documented in many places, and the responsibility
for security explicitly left up to the user.  Not only that but an
earlier attempt at "safe pickling" was removed in Python 2.3 (IIRC)
since it didn't guarantee safety, and it wasn't considered worth the
considerable effort to audit the pickle code for vulnerabilities.

 > What I am asking for is the ability for application code
 > subclassing Unpickler to control how certain opcodes are evaluated
 > by overriding methods... something that *already exists*, just not
 > for the right ones needed to be adequately expressive.

Of course they already exist, and can be overriden.  I guess what
you're asking for is a promise that the interface won't change in
future versions of pickle.py.  That's the only difference between
overriding Unpickler.find_class and overriding Unpickler.load_reduce
(or any other method).
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/SQR43KOW2UDVY7JFO5PW4S6HKOQAF4ZM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Stephen J. Turnbull
Steven D'Aprano writes:

 > But if I'm distributing my code to others, the responsible thing to do 
 > is to think of the potential security risks about using pickle in my 
 > app, or library. What if they use it in ways that I didn't foresee, ways 
 > which *ought to be* safe except for my choice to use pickle?

If you have a choice, don't use pickle.  If you don't have a choice,
label your product "Uses pickle.  If you care about security, find out
what security issues that entails."

 > How do I use JSON to serialise an arbitrary instance of some class?

Ask Wes Turner about semantic JSON or whatever it is he frequently
advocates for providing more type information to JSON codecs.

 > How do I know which other serialisation format is right?

That's your problem.  We can advise you once you present your
application and threat model(s).  It does depend on both.

 > What about those -- and they are a significant minority -- who are 
 > restricted to only what's in the stdlib?

What about them?

 > Some awfully clever chappy found a way to add a magical
 > "pickle.safeload()" function that did everything needed,
 > safely. Would you oppose it?

I never oppose magic, for wizards are subtle and quick to anger.  I
have no desire to be turned into a newt.  I just don't believe claims
like "function that does everything needed, safely."

 > If you do *actively oppose* adding a safe version of pickle, perhaps you 
 > should explain why.

Define "safe": what is pickle allowed to do, what applications will be
provided such "safety", and what threat model(s) is(are) being
considered?  Until somebody answers that, we all may as well sit this
one out.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/J7DQBQ2IB23STPICOMEGU3FTP7V2NBIF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] encode/decode for all objects

2020-07-15 Thread Stephen J. Turnbull
Michael A. Smith writes:

 > It seems to me that obj.encode("json") and str.decode("json"), for example,
 > would be a powerful feature,

This idea comes up a lot in various forms.  The most popular lately is
an optional __json__ dunder, which really would avoid the complication
of working with custom JSONEncoders.  That hasn't got a lot of takeup,
though.  Perhaps we could broaden the appeal by generalizing it to
obj.__serialize__(protocol='json'), but that looks like overengineering
to me.

I think tying it to the codecs registry is probably going to get a lot
of pushback, at least when you get to the point where you're
discussing with the senior core devs.  In Python terms like "codec"
and methods like .encode and .decode are very deliberately tied to
character encodings.  In Python 2 there were "transcodings" like gzip,
rarely used, discarded in Python 3, and not missed.

 > Right now, if I want to json.dumps a MappingProxyType, I believe I
 > have to pass a custom JSONEncoder to json.dumps explicitly every
 > time I call it.

That's exactly the kind of thing we have 'def' for though.

 > But I think I should be able to register one, and then just call
 > thing.encode('json').

Think your MappingProxyType example through.  It's going to be a lot
more complicated than "register and just call", I think.

 > I could call codecs.encode(thing, 'json'), but I think maybe I
 > shouldn't have to import codecs or json into my modules to do this.

That will never fly, I think.  Text encoding is privileged in the open
builtin and on str and bytes because every single Python program must
do it (the source is *always* bytes and *always* has to be decoded to
text), and because *only* text and bytes need .encode and .decode
respectively.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HPKIUUIJJ3QNYEH7RDYZZ5J55L5ORJBC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] add !p to pprint.pformat() in str.format() an f-strings

2020-07-15 Thread Charles Machalow
Right now in str.format(), we have !s, !r, and !a to allow us to call str(), 
repr(), and ascii() respectively on the given expression.

I'm proposing that we add a !p conversion to have pprint.pformat() be called to 
convert the given expression to a 'pretty' string.

Calling
```
print(f"My dict: {d!p}")
```

is a lot more concise than:

```
import pprint
print(f"My dict: {pprint.pformat(d)}")
```

We may even be able to have a static attribute stored to change the various 
default kwargs of pprint.pformat().
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/LNQEA6IYBS5B7NMGC3P4JFPCSR33W4C6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: python interpreter docker builder

2020-07-15 Thread Wes Turner
Re: manylinux wheels in Alpine docker (musl (with glibc optionally also
installed))

"Clarify that pip wheels are incompatible with alpine-based images"
https://github.com/docker-library/docs/issues/904

"Install manylinux wheel although it's not officially supported by the host"
https://github.com/pypa/pip/issues/3969#issuecomment-495991727 :

> ```bash
> RUN echo 'manylinux1_compatible = True' >
/usr/local/lib/python3.7/site-packages/_manylinux.py
> RUN python -c 'import sys; sys.path.append(r"/_manylinux.py")'
> ```

On Tue, Apr 7, 2020, 10:58 AM João Santos  wrote:

> On Tuesday, 7 April 2020 10:52:36 CEST M.-A. Lemburg wrote:
> > Hi Antonio,
> >
> > you may want to have a look at the Alpine images for Python
> > and this optimized variant:
> >
> > https://github.com/jfloff/alpine-python
> >
> > They also come with dev tools installed. Still, they are overall
> > rather clunky to ship around. On the plus side, you can layer
> > images in docker, so that applications could reuse the
> > base images, once downloaded.
> >
> > Thanks,
> >
> > >>> Python Projects, Coaching and Support ...https://www.egenix.com/
> > >>> Python Product Development ...https://consulting.egenix.com/
> >
> > 
> >
> > ::: We implement business ideas - efficiently in both time and costs :::
> >eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
> > D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
> >Registered at Amtsgericht Duesseldorf: HRB 46611
> >https://www.egenix.com/company/contact/
> >  https://www.malemburg.com/
> >
> > On 4/3/2020 3:18 PM, Antonio Cavallo wrote:
> > > Hi Marc-Andre,
> > >
> > > yes pyrun is sort of what I had in mind :) That would be like the jre
> > > part of the jdk if you're familiar with java.
> > >
> > > Ideally users will download the jre and use for running applications
> > > (eg. pyrun) but if there's a need for an extension build one need to
> > > have a compiler.. now given the plethora of linux distros that's a
> > > logistic nightmare.
> > >
> > > So my little project does that (following the linux from scratch
> > > guidelines): it builds the toolchain (minus libc) the compiler and the
> > > python interpreter in one giant (at the moment) tarball. It should be
> > > easy to extract from it the runtime part (eg. the pyrun equivalent or
> > > the miniconda).
> > >
> > > I hope this makes a bit more sense.
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > > On Fri, 3 Apr 2020 at 04:46, M.-A. Lemburg  > >
> > > > wrote:
> > > Hi Antonio,
> > >
> > > could you please spell out your requirements a bit more clearly ?
> > >
> > > I have a hard time trying to understand what you're after.
> > > It seems to be about some sort of Python extension building
> > > environment for Linux, but I could be wrong.
> > >
> > > You normally don't need to build Python itself just to build an
> > > extension.
> > >
> > > If you're looking for a standardized Python build for Linux,
> > > PyRun might be what you want: http://pyrun.org/
> > >
> > > Thanks,
> > >
> > > Professional Python Services directly from the Experts (#1, Apr 03
> > > 2020)
> > >
> > > >>> Python Projects, Coaching and Support ...
> > > >>> https://www.egenix.com/
> > > >>> Python Product Development ...
> > > >>> https://consulting.egenix.com/
> > >
> > >
>  __
> > > __
> > >
> > > ::: We implement business ideas - efficiently in both time and
> costs
> :::
> > >eGenix.com Software, Skills and Services GmbH
> Pastor-Loeh-Str.48
> > > D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
> > >Registered at Amtsgericht Duesseldorf: HRB 46611
> > >https://www.egenix.com/company/contact/
> > >  https://www.malemburg.com/
> > >
> > > ___
> > > Python-ideas mailing list -- python-ideas@python.org
> > > To unsubscribe send an email to python-ideas-le...@python.org
> > > https://mail.python.org/mailman3/lists/python-ideas.python.org/
> > > Message archived at
> > >
> https://mail.python.org/archives/list/python-ideas@python.org/message/42V
> > > LPXWZKET6L3PIXSTIT2DN4E4M25VF/ Code of Conduct:
> > > http://python.org/psf/codeofconduct/
> >
> > ___
> > Python-ideas mailing list -- python-ideas@python.org
> > To unsubscribe send an email to python-ideas-le...@python.org
> > https://mail.python.org/mailman3/lists/python-ideas.python.org/
> > Message archived at
> >
> https://mail.python.org/archives/list/python-ideas@python.org/message/74UAJ
> > 5YKJU3VQPFNVP2QUCPNT656Z7EE/ Code of Conduct:
> > http://python.org/psf/codeofconduct/
>
> It's a bad idea to use alpine

[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Random832



On Wed, Jul 15, 2020, at 21:16, Chris Angelico wrote:
> Are you sure of that? I don't have any examples to hand, but are you
> able to pickle something identified as pkg.module.cls(x)?

This produces find_class('pkg.module', 'cls').

Doing pkg.module.cls.method produces find_class('builtins', 
'getattr')(find_class('pkg.module', 'cls'), 'method')

> > Second of all, with no way to exfiltrate, why is reading arbitrary 
> > attributes from objects problematic?
> 
> Because the moment you can read arbitrary attributes from arbitrary
> objects, Python becomes impossible to sandbox.

Not if you can't call them.
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/UFD7XKCG4JG2KGKGIQYCFY6RJ5RSHLIG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: New clause in FOR and WHILE instead of ELSE

2020-07-15 Thread Random832
On Tue, Jul 14, 2020, at 17:55, Rob Cliffe wrote:
> > What if "instead of a special kind of if clause that can only be placed 
> > after a loop", we simply defined these three special expressions [usable in 
> > any if/elif statement] to reference special boolean flags that are set 
> > after exiting any loop?
> The problem is: how long would these "special boolean flags" be retained?
> Could they still be tested
>      100 lines of code later (assuming no other loops were executed)?
>      After returning from a function?
>      Inside a new function call?
>          etc.
> This would violate the principle of ... I can't remember the computer 
> science name for it, but let's call it ... local transparency.
> Rob Cliffe

Sorry if this was unclear, but my idea is that they would be per-frame like 
local variables. Perhaps they could even be implemented *as* local variables, 
with assign statements emitted during loops by the compiler if they are used 
anywhere in the function. If that violates 'local transparency', so does using 
the same scope for ordinary local variables [such as, say, the iteration 
variable of a for loop, which can also be used 100 lines of code later].

And of course PEP 8 would forbid using them anywhere other than directly after 
a loop, but allowing them to be used in any if clause prevents you from having 
two different kinds of compound statement, which can't be mixed together, that 
both begin with the word "if".
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/D52HTWGHHPBVLQQBYK7O6BDWS6EFSKTF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Random832
On Wed, Jul 15, 2020, at 07:40, Steven D'Aprano wrote:
> On Tue, Jul 14, 2020 at 09:47:15PM -0400, Random832 wrote:
> 
> > I was asking for the current Unpickler class, which currently has a 
> > whitelist hook for loading globals, to be modified to also have a 
> > whitelist hook so that an application can provide a function that 
> > looks at a callable and its arguments that the pickle proposes to 
> > call, and can choose to either evaluate it, raise an error, or return 
> > a substitute value.
> 
> Could you provide a proof of concept subclass?

I was thinking of something like this... this is largely a trivial modification 
of the pure-python unpickler, but there's no methods that can be overridden for 
this effect in the C one.


class MyUnpickler(pickle._Unpickler):
# this method is intended to be overriden by subclasses
def do_call(self, func, *a, **k):
#print(f"blocked call {func}(*{a}, **{k})")
#return None
raise NotImplementedError("This unpickler can't handle this pickle")

# these methods are defined the same as in _Unpickler except for the use of 
do_call
def _instantiate(self, klass, args):
if (args or not isinstance(klass, type) or
hasattr(klass, "__getinitargs__")):
try:
value = do_call(klass, *args)
except TypeError as err:
raise TypeError("in constructor for %s: %s" %
(klass.__name__, str(err)), sys.exc_info()[2])
else:
value = do_call(klass.__new__, klass)
self.append(value)

def load_newobj(self):
args = self.stack.pop()
cls = self.stack.pop()
obj = self.do_call(cls.__new__, cls, *args)
self.append(obj)

def load_newobj_ex(self):
kwargs = self.stack.pop()
args = self.stack.pop()
cls = self.stack.pop()
obj = self.do_call(cls.__new__, cls, *args, **kwargs)
self.append(obj)

def load_reduce(self):
stack = self.stack
args = stack.pop()
func = stack[-1]
stack[-1] = self.do_call(func, *args)

dispatch = pickle._Unpickler.dispatch.copy()
# load_inst and load_obj use _instantiate and don't need to be overridden 
directly
dispatch[pickle.NEWOBJ[0]] = load_newobj
dispatch[pickle.NEWOBJ_EX[0]] = load_newobj_ex
dispatch[pickle.REDUCE[0]] = load_reduce


def loads(s, /, *, fix_imports=True, encoding="ASCII", errors="strict", 
buffers=None, unpickler=pickle.Unpickler):
if isinstance(s, str):
raise TypeError("Can't load pickle from unicode string")
file = io.BytesIO(s)
return unpickler(file, fix_imports=fix_imports, buffers=buffers,
  encoding=encoding, errors=errors).load()
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/PGYB6ARHJMUAC4TY4X2HXU4ANZ33KIUN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Chris Angelico
On Thu, Jul 16, 2020 at 11:13 AM Random832  wrote:
>
> On Wed, Jul 15, 2020, at 08:14, Chris Angelico wrote:
> > That's fair, but are you actually guaranteeing that it will never read
> > arbitrary attributes from objects?
>
> First of all, reading an attribute of an object in a pickle requires the 
> getattr function. Even currently, you can substitute your own function for 
> getattr in find_class, and with my proposal you wouldn't have to because you 
> could control attempts to evaluate even the real getattr function.
>

Are you sure of that? I don't have any examples to hand, but are you
able to pickle something identified as pkg.module.cls(x)?

> Second of all, with no way to exfiltrate, why is reading arbitrary attributes 
> from objects problematic?

Because the moment you can read arbitrary attributes from arbitrary
objects, Python becomes impossible to sandbox.

ChrisA
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/AHDQVMILKSOKYQPOLRI36CSFV2WS24D2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Random832
On Wed, Jul 15, 2020, at 08:14, Chris Angelico wrote:
> That's fair, but are you actually guaranteeing that it will never read
> arbitrary attributes from objects? 

First of all, reading an attribute of an object in a pickle requires the 
getattr function. Even currently, you can substitute your own function for 
getattr in find_class, and with my proposal you wouldn't have to because you 
could control attempts to evaluate even the real getattr function.

Second of all, with no way to exfiltrate, why is reading arbitrary attributes 
from objects problematic?
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4ZDXYU7JGEFWYNCO35FCB6OXBOGSXZAQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Random832
On Wed, Jul 15, 2020, at 07:54, Edwin Zimmerman wrote:
> The idea that the pickle module can be made "safe" is magical thinking. 
>  Pickle's attack surface is just too large and too powerful.

I don't think that makes something *inherently* unsafe, it just makes it 
difficult to make it safe. The problem I have is with the idea that it is 
*conceptually inevitable* [in the same way as, say, eval] for it to be unsafe, 
and therefore that it's not worth fixing bugs or adding whitelist features or 
doing anything other than saying "oh well it's their fault for using pickle" 
if/when an exploit is found.

[that said, it might also be a worthwhile project to make an alternate 
"advanced de/serializer" that primarily works by creating empty objects [i.e. 
with object.__new__(cls)] and populating their slots/dictionaries by assignment 
rather than by executing any constructor code, though it would need special 
support for extension types with C structures]

> As I said in a previous message, a stupid pickle fuzzer I wrote several 
> years ago took about 60 seconds to start finding bugs (on an
> old slow-as-molasses single-core Intel Atom processor).  A more 
> intelligent fuzzer, on a much more powerful machine would probably
> do just as well today.  It would help slightly to throw out the _pickle 
> module and default to the pure Python version, but even then
> I wouldn't consider it anywhere close to secure.
> 
> That said, I agree with the idea of giving users an easier way to 
> control what pickle does.  I think that any such modifications
> should continue to make clear that pickle has not magically become 
> "safe".
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/YR3WET2G5S42MUBXPN7BAFGAE7XYSJEH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] encode/decode for all objects

2020-07-15 Thread Michael A. Smith
I was playing with the codecs module and realized that there's untapped
potential to use them for de/serialization. It's easy enough to register a
codec for some case, but very few objects (I think only strings and bytes
and their stream cousins) have native encode/decode methods.

It seems to me that obj.encode("json") and str.decode("json"), for example,
would be a powerful feature, if it were tied into the native codecs
registry, enabling users to simplify a lot of serialization code and
implement or tie-in any codec that makes sense.

Right now, if I want to json.dumps a MappingProxyType, I believe I have to
pass a custom JSONEncoder to json.dumps explicitly every time I call it.
But I think I should be able to register one, and then just call
thing.encode('json'). I could call codecs.encode(thing, 'json'), but I
think maybe I shouldn't have to import codecs or json into my modules to do
this.

What do you think?


In case anyone is interested, here's a simple registration of json as a
codec that works today:


import codecs, json


def encode(obj):
try:
size = len(obj)
except TypeError:
size = 1
return json.dumps(obj), size

def decode(obj):
return json.loads(obj), len(obj)
codec_info = codecs.CodecInfo(
name='json',
encode=encode,
decode=decode
)

codecs.register({'json': codec_info}.get)
print(codecs.encode({'a':1}, 'json'))  # etc
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/QB2F2WA32HUVOHAZEZHY6MEVCFAEYB2T/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: New clause in FOR and WHILE instead of ELSE

2020-07-15 Thread Steven D'Aprano
On Wed, Jul 15, 2020 at 05:45:05AM +, Steve Barnes wrote:

> Can I suggest that for loops the `else` would be a lot clearer if it 
> was spelt `finally` as was done for PEP-0341 for try blocks and that 
> we might possibly need one or more `on_…` clauses such as `on_break` 
> and `on_finish` I think that this would be a lot clearer:

Sorry Steve, "finally" would be a terrible name because it behaves 
nothing like try...finally. In try blocks, the finally block is *always* 
executed, even if you raise, even if you return.

(To be precise, there are odd and unusual cases where finally won't be 
executed, such as if the interpreter process is `kill -9`'ed, or if a 
power surge fries the CPU. But under normal processing, finally always 
runs.)

But the for...finally (renamed from for...else) is not like that. If 
anything, it's the opposite of finally: it is a block designed to be 
skipped, not a block designed to always run.

Any of `break`, `return` or `raise` will cause the for...finally clause 
to be skipped. So we would be swapping one form of confusion to another 
("why is my finally clause not executed?").



-- 
Steven
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/UGNODYQOAWKS5QRYG352YUW6DLJEDGUP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Chris Angelico
On Wed, Jul 15, 2020 at 9:37 PM Steven D'Aprano  wrote:
>
> On Wed, Jul 15, 2020 at 11:24:17AM +1000, Chris Angelico wrote:
> > So if you're distributing your code, then maybe you don't use pickle.
>
> Sure. What do I use to serialise my complex data structure? I guess I
> could write out the repr and then call eval on it, that should be
> fine... *wink*

Maybe don't HAVE an arbitrarily complex data structure for
serialization. Maybe have a way to turn the in-memory representation
into a much simpler structure, serialize that, and then load from your
saved form.

It'll make your code a lot easier to reason about and refactor, since
you're no longer intrinsically binding your code to your save format.

> I'm not a pickle expert, but I don't think that's quite right. pickle
> has to be able to execute arbitrary code in order to be able to
> de-serialise arbitrary pickles, but that doesn't mean it has to
> de-serialise arbitrary pickles if you aren't expecting arbitrary
> pickles.
>
> Random beat it to me by suggesting a white-list, but I was thinking the
> same way. The pickle protocol has to be able to deal with arbitrary
> instances, but very few apps using pickle need to, or want to, accept
> arbitrary instances. If my app serialised Widgets and Gadgets, then it
> ought to be an error to attempt to deserialise anything else.
>
> Then all I need do is ensure that the Widget and Gadget classes are
> secure, not the entire Python universe :-)

If that's what you want, then have a way to serialize Widgets and
Gadgets, and *not* a way to serialize arbitrary objects. That, to me,
sounds more like "enhanced JSON" than "magically safe pickle".

> Security is always about tradeoffs, and we shouldn't let the idea of
> some unattainable perfectly secure pickle get in the way of improving
> the safety of pickle.

Nor should we let the idea of a secure pickle get in the way of
improving the functionality of safer options.

> > If someone claims they've created a way to allow untrusted users to
> > insert code into your Python programs and have it execute, but they've
> > made it safe, would you oppose its inclusion in the stdlib?
>
> But that's not really what we're asking for. We're asking for a way to
> *avoid* executing arbitrary code, while still allowing *trusted* objects
> to be depickled.

Except that you are. It's equivalent to trying to create a safe
version of eval() instead of building a simple arithmetic expression
parser. You're starting from danger and trying to patch until it's
safe, instead of starting from safety and adding functionality until
it's usable.

Remember: If you have insufficient functionality, you'll know about
it; if you are insufficiently secure, you won't know till it's too
late.

> > You want "pickle but magically able to know what's safe and what's
> > not"?
>
> Of course not. But maybe I want to be able to tell pickle what I think
> is safe, and have everything else fail.
>

That's fair, but are you actually guaranteeing that it will never read
arbitrary attributes from objects? Can pickle grab a module or
function, pick up a dunder from it, and go to town? Are you able to
give a total 100% guarantee that it cannot? If not, how do you know
that it's safe?

Edwin has given further information on the inherent unsafe nature of
pickle. It should be used for trusted pickles, NOT as a basis for some
magical "safe" parser.

ChrisA
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/ZDOJSZJOPKVY2BSQJZY6XVHLQ7ZLIQBY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Edwin Zimmerman
Random832 [mailto:random...@fastmail.com] wrote:
> On Tue, Jul 14, 2020, at 21:24, Chris Angelico wrote:
> > I actively oppose it because it isn't possible. Anything that is safe
> > will not have all of pickle's functionality. A nerfed version of
> > pickle that can only unpickle a tiny handful of core data types is no
> > better than other options that already exist. The entire point of
> > pickling arbitrary objects is that you can unpickle arbitrary objects.
> 
> I don't understand why no-one's engaging with what I actually suggested. I 
> was not asking for a magically safe or arbitrarily
restricted
> pickle function.
> 
> I was asking for the current Unpickler class, which currently has a whitelist 
> hook for loading globals, to be modified to also
have a
> whitelist hook so that an application can provide a function that looks at a 
> callable and its arguments that the pickle proposes
to call,
> and can choose to either evaluate it, raise an error, or return a substitute 
> value.
> 
> > That's inherently unsafe if there is any possibility that the pickle
> > file came from an untrusted user, and I do indeed oppose plans to try
> > to make pickle what it isn't.
> 
> We already have one whitelist hook, why not another?
> 
> The idea that the pickle format is "inherently unsafe" and cannot be made 
> safe is magical thinking. 

The idea that the pickle module can be made "safe" is magical thinking.  
Pickle's attack surface is just too large and too powerful.
As I said in a previous message, a stupid pickle fuzzer I wrote several years 
ago took about 60 seconds to start finding bugs (on an
old slow-as-molasses single-core Intel Atom processor).  A more intelligent 
fuzzer, on a much more powerful machine would probably
do just as well today.  It would help slightly to throw out the _pickle module 
and default to the pure Python version, but even then
I wouldn't consider it anywhere close to secure.

That said, I agree with the idea of giving users an easier way to control what 
pickle does.  I think that any such modifications
should continue to make clear that pickle has not magically become "safe".

--Edwin

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/4SMPDLZWQUWDC7EH4X53NQYNUADW5MF7/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Steven D'Aprano
On Tue, Jul 14, 2020 at 09:47:15PM -0400, Random832 wrote:

> I was asking for the current Unpickler class, which currently has a 
> whitelist hook for loading globals, to be modified to also have a 
> whitelist hook so that an application can provide a function that 
> looks at a callable and its arguments that the pickle proposes to 
> call, and can choose to either evaluate it, raise an error, or return 
> a substitute value.

Could you provide a proof of concept subclass?


-- 
Steven
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/7UGE2KX33ZWH5TB2YE5VU3TJAWGHSVZU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Steven D'Aprano
On Wed, Jul 15, 2020 at 11:24:17AM +1000, Chris Angelico wrote:

> It's correct far more often than you might think. There's a LOT of
> code out there where the Python source code has the exact same
> external access permissions as its config files - often because
> there's no access to either.

Um, yes? Safe use-cases is not the issue here. It's the unsafe use-cases 
that are important. Especially the use-cases that people may think are 
safe but actually aren't.

To stick to the seat belt analogy for a moment... we don't reject seat 
belts in cars because most of the time cars are safely parked in a 
garage. We add them for the times that cars are in motion at speed.

Improving the security of pickle shouldn't be done for the sake of cases 
where the security of pickle is irrelevent. It should be done for the 
sake of cases where it is necessary, especially for those cases where 
the developer thinks that security isn't necessary, but they are 
mistaken.


> So if you're distributing your code, then maybe you don't use pickle.

Sure. What do I use to serialise my complex data structure? I guess I 
could write out the repr and then call eval on it, that should be 
fine... *wink*


[...]
> > Okay, let's say that somebody else did the work. Some awfully clever
> > chappy found a way to add a magical "pickle.safeload()" function that
> > did everything needed, safely. Would you oppose it?
> >
> > (The old unsafe one would presumably have to remain for backwards
> > compatibility, or for the cases which are inherently unsafe.)
> 
> I would ask them which laws of physics they violated, since pickle
> inherently has to be able to execute arbitrary code in order to be
> able to do everything it needs to.

I'm not a pickle expert, but I don't think that's quite right. pickle 
has to be able to execute arbitrary code in order to be able to 
de-serialise arbitrary pickles, but that doesn't mean it has to 
de-serialise arbitrary pickles if you aren't expecting arbitrary 
pickles.

Random beat it to me by suggesting a white-list, but I was thinking the 
same way. The pickle protocol has to be able to deal with arbitrary 
instances, but very few apps using pickle need to, or want to, accept 
arbitrary instances. If my app serialised Widgets and Gadgets, then it 
ought to be an error to attempt to deserialise anything else.

Then all I need do is ensure that the Widget and Gadget classes are 
secure, not the entire Python universe :-)

As I said, I'm not an expect, but five minutes reading this:

https://rushter.com/blog/pickle-serialization-internals/

allows me to confidently pontificate on the subject *wink*

The depickling virtual machine (pickle machine or PM) is not Turing 
complete. It has no loops or conditionals. It's a dumb machine that 
takes a sequence of op-codes, executing them in order, and then halt.

The GLOBAL op-code (by default) will import any module, and use any 
function from that module. That's dangerous; an option to restrict what 
modules and functions can be called by the PM would go a long way to 
reducing the attack surface of pickle. (I think.)

Random's idea of white-listing seems like a promising approach to me. 
Even if it doesn't make pickle "safe" in some absolute sense, it will 
make it *less unsafe* and reduce the attack surface for people using 
pickle.

Security is always about tradeoffs, and we shouldn't let the idea of 
some unattainable perfectly secure pickle get in the way of improving 
the safety of pickle.


> If someone claims they've created a way to allow untrusted users to
> insert code into your Python programs and have it execute, but they've
> made it safe, would you oppose its inclusion in the stdlib?

But that's not really what we're asking for. We're asking for a way to 
*avoid* executing arbitrary code, while still allowing *trusted* objects 
to be depickled.


> You want "pickle but magically able to know what's safe and what's
> not"?

Of course not. But maybe I want to be able to tell pickle what I think 
is safe, and have everything else fail.


-- 
Steven
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MBJB2JG47APNHDON2EILYAS7DOAUZGR2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Pickle security improvements

2020-07-15 Thread Antoine Pitrou
On Wed, 15 Jul 2020 09:45:06 +1000
Steven D'Aprano  wrote:
> 
> And that's the risk: can I guarantee that there is no clever scheme by 
> which an attacker can fool me into unpickling malicious code? I need to 
> be smarter than the attacker, and more imaginative, and to have thought 
> as long and hard about the problem as they have.

A rather straightforward way to guarantee it would be to sign pickles
cryptographically.  Of course, the private signing key should not be
compromised :-)

Regards

Antoine.

___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DQ6XBCB3LAAMTPWMQFUBSMNPJVS3UNEL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: New clause in FOR and WHILE instead of ELSE

2020-07-15 Thread Jonathan Fine
I'm really glad that Олег Комлев has posted this suggestion to the list.
Thank you!

I found myself using this construction, and in December 2019 (that seems a
long time ago) I discussed it face-to-face with Paul Piwek. He found this
highly relevant article
https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops

Here's a brief (and selective) summary of this SO page. The question was
asked in 2012. The original poster wrote "No matter how I think about it,
my brain can't progress seamlessly from the for statement to the else
block."

One of the answers references a talk by Raymond Hettinger, which "briefly
addresses the history of for ... else". He attributes the concept to Don
Knuth, and says that if Guido was thinking about the future he (GvR) would
have called it no_break instead of else, so everyone would know what it did.

I highly recommend that you watch RH's talk, 15:50 to 19:00 (min:sec).
Transforming Code into Beautiful, Idiomatic Python
https://www.youtube.com/watch?v=OSGv2VnC0go&feature=youtu.be&t=950

The Stackoverflow page also references a summary of earlier discussions
that Steven D'Aprano kindly prepared and posted to this list (in 2009).
https://mail.python.org/pipermail/python-ideas/2009-October/006155.html

That's the end of my SO summary. In addition, there's Don Knuth's paper
Structured Programming with goto statements (1974)
Reprinted in https://www-cs-faculty.stanford.edu/~knuth/lp.html

By the way, I happen to have a copy of this book (typeset by TeX, of
course) and have more than once read the 1974 goto paper. (There we go. A
loop with a break.)

If you don't have ready access to a copy, you might like to look at
http://people.cs.pitt.edu/~zhangyt/teaching/cs1621/goto.slides.pdf
http://www.kohala.com/start/papers.others/knuth.dec74.html

I think that's enough for now. And thank you again Олег, for posting your
suggestion to the list.

-- 
Jonathan
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HIGH2DVFYDNAWVVXRZNYQ2UEYFVNI3XE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: New clause in FOR and WHILE instead of ELSE

2020-07-15 Thread Mathew Elman
The point is that `for-else` reads like "do this for loop ELSE (or but if
you can't loop) do this", i.e. roughly equivalent to this:

> try:
> loop_entered = False
> for loop_entered, elem in enumerate(iterable, start=1):
>pass
> assert loop_entered
> except AssertionError:
> print("loop not entered")
>
or

> loop_entered = False
> for loop_entered, elem in enumerate(iterable, start=1):
> pass
> if loop_entered:
> pass
> else:
> print("loop not entered")
>

But that isn't what it means. It means "do this for loop and if you
deliberately break out, continue ELSE (or if you don't break out) do this".
i.e. roughly equivalent to this:

> loop_broken = False
> for elem in iterable:
> if should_break(elem):
> loop_broken = True
> break
> if not loop_broken:
> print("you didn't break from the loop you maybe entered...")
>
or

> loop_broken = False
> for elem in iterable:
> if should_break(elem):
> loop_broken = True
> break
> if loop_broken:
>
pass
>
else:
>
print("you didn't break from the loop you maybe entered...")
>

which is not intuitive because `else` reads like it handles the unexpected
case, which one would have guessed was either breaking out or not entering
in the first place.

On Wed, 15 Jul 2020 at 09:23, Dominik Vilsmeier 
wrote:

> But `finally` with a `for` loop is redundant since the code can be placed
> just after the loop. For `try/except` it's a different situation since the
> exception might bubble up, so "normal" code after the `try` won't be
> reached.
>
> Also `on_break` doesn't seem really important since that code can be
> executed inside the loop right before the `break`.
>
> We already have `else` for `on_finish` and I think when recalling the
> analogy to exceptions it's not that confusing: a `try` block can be exited
> either normally (because all code has been executed) or because it raised
> an exception; here `else` means it exited normally. Similarly a `for` loop
> can terminate either normally by executing all iterations or because a
> `break` occurred; and similarly `else` means it terminated normally.
> On 15.07.20 08:47, Mathew Elman wrote:
>
> But in `for...else` the `else` call isn't always called, so changing
> `else` for `finally` doesn't make sense. What you're suggesting is
> replacing `else` with `on_finish` and adding `finally` and `on_break`.
>
> I agree that having `finally` could make the use cases of `else` clearer,
> but I am not convinced renaming "else" to "on_finish" would help the
> confusion for the 0 iteration case.
>
> I think that since this suggestion doesn't help with the 0 iteration case
> (my first idea here didn't either), it feels like added extra compound
> statements need to be immediately intuitive to be worth having - either
> because they read like a sentence or parallel existing python e.g.
> `try-except-else-finally` or `if-elif-else` etc.
>
>
> On Wed, 15 Jul 2020 at 06:47, Steve Barnes  wrote:
>
>> Can I suggest that for loops the `else` would be a lot clearer if it was
>> spelt `finally` as was done for PEP-0341 for try blocks and that we
>> might possibly need one or more `on_…` clauses such as `on_break` and `
>> on_finish` I think that this would be a lot clearer:
>>
>>
>>
>> for i in range(N):
>>
>> if i > 3:
>>
>> break;
>>
>> on_break:  # Called if loop was broken
>>
>> print(i)
>>
>> on_finish:  # Called if loop was not broken
>>
>> print("Loop Completed")
>>
>> finally:  # Always called (replaces for…else)
>>
>> print("Loop Ended")
>>
>>
>>
>> Which I think would be a lot easier for newcomers to learn than
>> try…for…else…except…else e.g.:
>>
>>
>>
>> try:
>>
>> for i in range(N):
>>
>>if i > 3:
>>
>> break;
>>
>>elif i % 2 == 0:
>>
>> raise ValueError("Odds Only");
>>
>> else: # to if
>>
>> print(i)
>>
>> else:  # Else to loop
>>
>> print("Loop Completed")
>>
>> except ValueError as err:
>>
>> print(err)
>>
>> else:  # to try
>>
>> print("No Exception")
>>
>> finally:
>>
>> print("Try Ended")
>>
>>
>>
>> Where the multitude of elses makes my eyes cross.
>>
>>
>>
>> Steve Barnes
>> ___
>> Python-ideas mailing list -- python-ideas@python.org
>> To unsubscribe send an email to python-ideas-le...@python.org
>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-ideas@python.org/message/MKAAWV6OT7SRIHTDOAEA3OHV6ZLSGLE2/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
> Notice:
> This email is confidential and may contain copyright material of members
> of the Ocado Group. Opinions and views expressed in this message may not
> necessarily reflect the opinions and views of the members of the Ocado
> Group.
>
> If you are not the intended recipient, please notify us immediately and
> delete all copies of

[Python-ideas] Re: New clause in FOR and WHILE instead of ELSE

2020-07-15 Thread Dominik Vilsmeier

But `finally` with a `for` loop is redundant since the code can be
placed just after the loop. For `try/except` it's a different situation
since the exception might bubble up, so "normal" code after the `try`
won't be reached.

Also `on_break` doesn't seem really important since that code can be
executed inside the loop right before the `break`.

We already have `else` for `on_finish` and I think when recalling the
analogy to exceptions it's not that confusing: a `try` block can be
exited either normally (because all code has been executed) or because
it raised an exception; here `else` means it exited normally. Similarly
a `for` loop can terminate either normally by executing all iterations
or because a `break` occurred; and similarly `else` means it terminated
normally.

On 15.07.20 08:47, Mathew Elman wrote:

But in `for...else` the `else` call isn't always called, so changing
`else` for `finally` doesn't make sense. What you're suggesting is
replacing`else` with `on_finish` and adding `finally` and`on_break`.

I agree that having `finally` could make the use cases of `else`
clearer, but I am not convinced renaming "else" to "on_finish" would
help the confusion for the 0 iteration case.

I think that since this suggestion doesn't help with the 0 iteration
case (my first idea here didn't either), it feels like added extra
compound statements need to be immediately intuitive to be worth
having - either because they read like a sentence or parallel existing
python e.g. `try-except-else-finally` or `if-elif-else` etc.


On Wed, 15 Jul 2020 at 06:47, Steve Barnes mailto:gadgetst...@live.co.uk>> wrote:

Can I suggest that for loops the `else` would be a lot clearer if
it was spelt `finally` as was done for PEP-0341 for try blocks and
that we might possibly need one or more `on_…` clauses such as
`on_break` and `on_finish` I think that this would be a lot clearer:

for i in range(N):

    if i > 3:

break;

on_break: # Called if loop was broken

print(i)

on_finish: # Called if loop was not broken

    print("Loop Completed")

finally: # Always called (replaces for…else)

    print("Loop Ended")

Which I think would be a lot easier for newcomers to learn than
try…for…else…except…else e.g.:

try:

    for i in range(N):

   if i > 3:

   break;

   elif i % 2 == 0:

   raise ValueError("Odds Only");

 else: # to if

print(i)

    else: # Else to loop

print("Loop Completed")

except ValueError as err:

print(err)

else:  # to try

    print("No Exception")

finally:

print("Try Ended")

Where the multitude of elses makes my eyes cross.

Steve Barnes

___
Python-ideas mailing list -- python-ideas@python.org

To unsubscribe send an email to python-ideas-le...@python.org

https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at

https://mail.python.org/archives/list/python-ideas@python.org/message/MKAAWV6OT7SRIHTDOAEA3OHV6ZLSGLE2/
Code of Conduct: http://python.org/psf/codeofconduct/


Notice:
This email is confidential and may contain copyright material of
members of the Ocado Group. Opinions and views expressed in this
message may not necessarily reflect the opinions and views of the
members of the Ocado Group.

If you are not the intended recipient, please notify us immediately
and delete all copies of this message. Please note that it is your
responsibility to scan this message for viruses.

References to the "Ocado Group" are to Ocado Group plc (registered in
England and Wales with number 7098618) and its subsidiary undertakings
(as that expression is defined in the Companies Act 2006) from time to
time. The registered office of Ocado Group plc is Buildings One & Two,
Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.


___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/3ZPJDOTFCCQALCHIVEIPFJBROG6JSHIY/
Code of Conduct: http://python.org/psf/codeofconduct/
___
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/W7M77OYSI4Z2TKPC7K7UIKUPEZVLRD77/
Code of Conduct: http://python.org/psf/codeofconduct/