Re: [Python-ideas] Fwd: Re: PEP: add a `no` keyword as an alias for `not`

2019-08-02 Thread Andrew Barnert via Python-list
On Aug 1, 2019, at 13:38, Daniel Okey-Okoro  wrote:
> 
> 
> > not a strong enough justification for breaking any code that uses "no" in 
> > any other way.
> 
> This is a very crucial point I didn't consider.
> 
> 
> 
> What if we could lexically limit it to `if no {{everything else in the if 
> block}}`?
> 
> I think that would sufficiently protect us from unintentionally breaking 
> people's code.

There are some cases where a “contextual keyword” that’s usable as an 
identifier outside of a specific syntactic construct could avoid ambiguity, but 
this isn’t one of them, because the thing immediately after the `if` in an if 
statement can be–and often is—an identifier. For example:

total = len(votes)
yes, no, other = (len(part) for part in partition_votes(votes))

if no >= total//2:
# etc.

I even found an actual example of the equivalent in some C++ code I had on my 
hard drive:

if (no == ask(…)) { 
// …
}

In Python, that would be:

if no == ask(…):

Also, even if that weren’t a problem, this would be very misleading syntax. If 
I can write `if no sales:` I’d expect to be able to write `if isopen and no 
sales:` or `0 if no sales else mean(sales)` or `skip = no sales` or any of the 
other things I can do with `not` and other operators rather than special syntax.

Also, I could still write `if no sales and isopen:`, but it would do the wrong 
thing if `no` is special syntax that reverses the sense of the `if` rather than 
a normal operator that binds more tightly than `and`.


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


Re: [Python-ideas] Re: Enhancing Zipapp

2020-01-08 Thread Andrew Barnert via Python-list
On Jan 8, 2020, at 01:09, Abdur-Rahmaan Janhangeer  wrote:
> 
> But now, a malicious program might try to modify the info file
> and modify the hash. One way to protect even the metadata is
> to hash the entire content
> 
> folder/
> file.py # we can add those in a folder if needed
> __main__.py
>infofile
> 
> Then after zipping it, we hash the zipfile then append the hash to the zip 
> binary
> 
> [zipfile binary][hash value]

How does this solve the problem? A malicious program that could modify the hash 
inside the info file could even more easily modify the hash at the end of the 
zip.

Existing systems deal with this by recognizing that you can’t prevent anyone 
from hashing anything they want, so you either have to store the hashes in a 
trusted central repo, or (more commonly–there are multiple advantages) sign 
them with a trustable key. If a malicious app modified the program and modified 
the hash, it’s going to be a valid hash; there’s nothing you can do about that. 
But it won’t be the hash in the repo, or it’ll be signed by the untrusted 
author of the malicious program rather than the trusted author of the app, and 
that’s why you don’t let it run. And this works just as well for hashes 
embedded inside an info file inside the zip as for hashes appended to the zip.

And there are advantages to putting the hash inside. For example, if you want 
to allow downstream packagers or automated systems to add distribution info 
(this is important if you want to be able to pass a second code signing 
requirement, e.g., Apple’s, as well as the zipapp one), you just have a list of 
escape patterns that say which files are allowed to be unhashed. Anything that 
appears in the info file must match its hash or the archive is invalid. 
Anything that doesn’t appear in the info file but does match the escape 
patterns is fine, but if it doesn’t match the escape patterns, the archive is 
invalid. So now downstream distributors can add extra files that match the 
escape patterns. (The escape patterns can be configurable—you just need them to 
be specified by something inside the hash. But you definitely want a default 
that works 99% of the time, because if developers and packagers have to think 
it through in every case instead of only in exceptional cases, they’re going to 
get it wrong, and nobody will have any idea who to trust to get it right.)


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


Re: [Python-ideas] Re: Enhancing Zipapp

2020-01-08 Thread Andrew Barnert via Python-list
On Jan 8, 2020, at 01:09, Abdur-Rahmaan Janhangeer  wrote:
> 
> Using the wheel-included zip (A), we can generate another zip file (B) with
> the packages installed. That generated zip file is then executed.

But that generated zip B doesn’t have a trustable hash on it, so how can you 
execute it?

If you keep this all hidden inside the zipapp system, where malicious programs 
can’t find and modify the generated zips, then I suppose that’s fine. But at 
that point, why not just install the wheels inside zip A into an auto-generated 
only-for-zip-A venv cache directory or something, and then just run zip A as-is 
against that venv?

> Zip format A solves the problem of cross-platforming.
> Normal solutions upto now like use solution B where you can't share
> your zips across OSes. 

You can still only share zips across OSs if you bundle in a wheel for each 
extension library for every possible platform. For in-house deployments where 
you only care about two platforms (your dev boxes and your deployment cluster 
boxes), that’s fine, but for a publicly released app that’s supposed to work 
“everywhere”, you pretty much have to download and redistribute every wheel on 
PyPI for every dependency, which could make your app pretty big, and require 
pretty frequent updates, and it still only lets you run on systems that have 
wheels for all your dependencies.

If you’re already doing an effective “install” step in building zip B out of 
zip A, why not make that step just use a requirements file and download the 
dependencies from PyPI? You could still run zip B without being online, just 
not zip A.

Maybe you could optionally include wheels and they’d serve as a micro-repo 
sitting in front of PyPI, so when you’re dependencies are small you can 
distribute a version that works for 95% of your potential users without needing 
to do anything fancy but it still works for the other 5% if they can reach PyPI.

(But maybe it would be simpler to just use the zip B as a cache in the first 
place. If I download Spam.zipapp for Win64 3.9, that’s a popular enough 
platform that you probably have a zip B version ready to go and just ship me 
that, so it works immediately. Now, if I copy that file to my Mac instead of 
downloading it fresh, oops, wrong wheels, so it downloads the right ones off 
PyPI and builds a new zipapp for my platform—and it still runs, it just takes a 
bit longer the first time. I’m not sure this is a good idea, but I’m not sure 
trying to include every wheel for every platform is a good idea either…)

But there’s a bigger problem than just distribution. Some extension modules are 
only extension modules for speed, like numpy. But many are there to interface 
with C libraries. If my app depends on PortAudio, distributing the extension 
module as wheels is easy, but it doesn’t do any good unless you have the C 
library installed and configured on your system. Which you probably don’t if 
you’re on Windows or Mac. A package manager like Homebrew or Choco can take 
care of that by just making my app’s package depend on the PortAudio package 
(and maybe even conda can?), but I don’t see how zipapps with wheels in, or 
anything else self-contained, can. And if most such packages eventually migrate 
to binding from Python (using cffi or ctypes) rather than from C (using an 
extension module), that actually makes your problem harder rather than easier, 
because now you can’t even tell from outside the code that there are external 
dependencies; you can distribute a single zipapp that works everywhere, but 
only in the sense that it starts running and quickly fails with an exception 
for most users.


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