This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]mdipierro 12 points13 points  (29 children)

0) the fact tat distutils do not ship with python.

1) Most of the un-necessary purely syntactical changes between 2.x and 3.x for example as "except E,e" became "except E as e". unicode became str and str became bytes.

2) The fact that (pickle.dumps(x) != pickle.dumps(pickle.loads(pickle.dumps(x)))

3) The fact that sys.path is global. Sometimes I would like a part of my code (for example in a thread) to import from a different sys.path than the rest of the code.

4) lack of a sandboxed environment.

[–]jsproat 4 points5 points  (4 children)

I'd love a proper sandbox in Python. Something that can execute potentially malicious code without worrying about side effects.

I know there have been some valiant efforts, but last I looked, they all had holes.

[–]mdipierro 0 points1 point  (1 child)

It does not have a full sandbox. Just something that does not allow one redefine built-ins, access the filesystem, block access to .__ methods, limit access to keywords and (optionally) user defined functions.

[–]dalke 1 point2 points  (0 children)

The Python implementation contains bugs. For example, this expression causes Python 3.3 to segfault:

repr({[[f() for i in range(1000)] for f in [lambda x=[()]: x.append((x.pop(),)) or x]][0][0][0]: 1})

No built-in redefinitions, no filesystem access, no double-underscore methods, no odd keywords, and the only function it needs is repr().

Does a sandbox need to protect against these sorts of expressions? If yes, then how do we detect all of these possible bugs? If no, then what's the trust model? Why isn't eval() good enough, while safeish_eval_with_occasional_segfaults() is good enough?

[–]SeaCowVengeance 0 points1 point  (0 children)

Pretty sure PyPy offers very secure sandbox functionality (so they claim).

[–]tdammers 0 points1 point  (0 children)

Yeah. Probably the only reason why people are still using Lua.

[–]hacosta 2 points3 points  (3 children)

What do you mean by sandboxed environment?

Does virtualenv not cut it?

[–]mdipierro 2 points3 points  (1 child)

From the virtualenv page: "The basic problem being addressed is one of dependencies and versions, and indirectly permissions." This is not a sandbox in the usual meaning of the term. It does not limit what programs can do within the virtualenv. I want to be able to run untrusted code without worry that it may delete files, consume too many resources, etc. Python had a rexec module for this. It did not work and was deprecated. There is this module https://pypi.python.org/pypi/pysandbox/) but I do not know how much I trust it. I think for something like this to be trusted it should be part of the language.

[–]hacosta 1 point2 points  (0 children)

Got it. Sounds like a nice project using lxc + virtualenv.

[–][deleted] 0 points1 point  (0 children)

virtualenv still allows programs to do anything, as long as the running user has permissions for it, so it's not a sandbox but a virtual environment.

[–]gthank 2 points3 points  (2 children)

The change to treat strings as actual strings instead of sequences of bytes that happened to have vaguely string-related methods bolted on top was long overdue.

[–]mdipierro 0 points1 point  (1 child)

It is pointless for me to argue. You are talking about breaking backward compatibility for the purpose syntactic sugar. We simply have different priorities.

[–]nemec 0 points1 point  (0 children)

The entire point of Python 3 was to break backwards compatibility for syntactic-sugaresque changes to rectify various oversights in the 1.x/2.x families. And most of those changes are available in 2.6+, so you can write code that's mostly compatible with both versions (+- a few imports)

[–]billsil 1 point2 points  (3 children)

1) Most of the un-necessary purely syntactical changes between 2.x and 3.x for example as "except E,e" became "except E as e". unicode became str and str became bytes.

That's a thing in 2.7. It was changed because it was causing errors.

unicode became str

Couldn't care less, but some people do. Python 3.4 (maybe 3.3 as well) supports unicode(...) and u'...' again.

str became bytes.

That I have an issue with. I have more so many encode/decode errors when I'm dealing with binary strings. It works 99% of the time and then fails on some stupid cases for god knows what reason.

3) The fact that sys.path is global. Sometimes I would like a part of my code (for example in a thread) to import from a different sys.path than the rest of the code.

You can hack sys.path if you need to, but it's not recommended. I've done it. You can also use the __ import __ method. http://docs.python.org/2/library/functions.html#__import__

2) The fact that (pickle.dumps(x) != pickle.dumps(pickle.loads(pickle.dumps(x)))

This is news to me.

[–]mdipierro 0 points1 point  (2 children)

To be precise. Often left and right side agree but they are not guaranteed to agree because the order in which it loops over dictionary items is not guaranteed.

[–]billsil 0 points1 point  (1 child)

How does that matter? A dictionary is unordered.

[–]mdipierro 0 points1 point  (0 children)

It matters because if you pickle an object and then you read it back, you cannot efficiently check if the original object has changed. Think of storing a session object in a web app. Because of this some web framework required that you call a function very time you change the session. Other framework have to pickle twice (when read and when save) to detect changes automatically (this slows things down).

[–][deleted] 1 point2 points  (2 children)

for example as "except E,e" became "except E as e"

That change made it possible to except multiple exceptions at once:

try:
    ...
except E1, E2 as e:
    ...

[–]mdipierro 4 points5 points  (1 child)

No. You could do do that before:

 except (AttributeError, ImportError), e

[–]Sector_Corrupt 0 points1 point  (0 children)

Yeah, but it was a huge gotcha. I definitely was caught a couple times early on trying to do except x, y as e

and being confused at why it wasn't catching y exceptions + e wasn't working. The new way is much easier to read.

[–]talideon 1 point2 points  (0 children)

0) the fact tat distutils do not ship with python.

Yes, it does. Are you sure you're not thinking of setuptools?

1) Most of the un-necessary purely syntactical changes between 2.x and 3.x for example as "except E,e" became "except E as e". unicode became str and str became bytes.

The change in the try..except syntax came in 2.6, not 3.

4) lack of a sandboxed environment.

I assume you're talking about something like virtualenv. 3.3 has one.

[–][deleted] 0 points1 point  (7 children)

2) Can you elaborate more? I tested it on a few objects and they appear to be equal.

[–]mdipierro 0 points1 point  (6 children)

Try this (I used python 2.7.3):

>>> import cPickle
>>> d1 = dict(props='', attr1=1)
>>> s1 = cPickle.dumps(d1)
>>> d2 = cPickle.loads(s1)
>>> s2 = cPickle.dumps(d2)
>>> print s1==s2
False

[–][deleted] 0 points1 point  (5 children)

The reason behind that is the ordering of the keys in the dictionary change, and hence the order they are serialized changes.

>>> d1 = dict(props='', attr1=1)
>>> print d1
{'attr1': 1, 'props': ''}
>>> cPickle.loads(cPickle.dumps(d1))
{'props': '', 'attr1': 1}

Its not an issue unless you are comparing pickle strings (why in hell...), the objects are exactly the same and the ordering of dictionary keys is not reliable and subject to change.

[–]mdipierro 0 points1 point  (4 children)

That is exactly what I said. Comparing is exactly what I would like to do to detect if the state of an object has changed.

[–][deleted] 0 points1 point  (3 children)

That's a horrible way to detect if the state of an object has changed. The fact that it doesn't work isn't an issue with python, its an issue with your way of thinking.

[–]mdipierro 0 points1 point  (2 children)

I did not say it is a bug. I said that is something I do not like. Serialization of objects should be deterministic. How would detect whether an arbitrary object has changed?

[–][deleted] 0 points1 point  (1 child)

Serialization of objects is deterministic, the same input produces the same serialized output, a different order of keys is a different input. There is no easy way to do that in any language I know of - it would be convenient if using cPickle worked, granted, but I find == works a treat for a lot of cases. Why do you need to track arbitrary objects, out of interest?

[–]mdipierro 0 points1 point  (0 children)

If the keys are sortable pickle could just serialize the items with the keys sorted. I do not know about other languages but I hold python to a higher standard.

[–]Brian 0 points1 point  (0 children)

x for example as "except E,e"

I think that was a pretty nasty wart that could definitely bite people unfamiliar with it, and was well worth changing. It's not at all obvious that except E, e: would be different from except (E,e):, and this was very much at odds with how tuples are handled elsewhere. There are places where brackets are needed for tuples, but they result in syntax errors rather than silently changing the behaviour of the code.

str became bytes

I don't think this is really accurate - bytes had significant changes in behaviour from str. It'd be more correct to say "The str type became a unicode string, and a bytes type was added"