Guido van Rossum added the comment:

Here's the promised explanation why I want to keep the getframe hack.  I'm sure 
it won't satisfy everyone, but this will have to do.

There are two parts to my argument.  TL;DR: (a) by implementing this hack, we 
will maximize user happiness; (b) I expect that all Python implementations can 
provide the functionality needed.

So why does this maximize user happiness?  First of all, enums are such simple 
objects that it's a disgrace to have an enum that isn't picklable.  But most 
users are lazy and lack imagination, so if they find they have to do extra work 
to ensure that something is picklable, they will make a judgement call -- is 
the extra work to make it picklable worth it?  Unfortunately they will try to 
make this judgment call in a fraction of a second, and they limited imagination 
they may well say "I can't imagine ever pickling this", save themselves the 
work, and move on.  If you think more than a second about the decision, you've 
wasted more time than it takes to type "module=__name__", so it's going to be a 
split-second decision.  But nevertheless, having to think about it and typing 
it is a distraction, and when you're "in the zone" you may prefer to spend your 
time thinking about the perfect names for your enum class and values rather 
than the red tape of making in picklable.

So, in my mind, it's a given that there will be many enums that are missing the 
module=__name__ keyword argument.  Moreover, it's likely that most of the time 
this will be fine -- you can get through most days just fine without ever 
reading or writing a pickle.  (For example, I very much doubt that I've ever 
pickled one of the flag values used by the socket module to define e.g. the 
address family, socket type, or protocol.)

But now you enter a different phase of your project, or one of your 
collaborators does, or perhaps you've released your code on PyPI and one of 
your users does.  So someone tries to pickle some class instance that happens 
to contain an unpicklable enum.  That's not a great experience.  Pickling and 
unpickling errors are often remarkably hard to debug.  (Especially the latter, 
so I have privately admonished Ethan to ensure that if the getframe hack 
doesn't work, the pickle failure should happen at pickling time, not at 
unpickle time.)  Once you've tracked down the source, you have to figure out 
the fix -- hopefully just typing the error message into Google will link back 
to a StackOverflow answer explaining the need to say "module=__name__".  But 
the damage is done, especially if the person encountering the pickling error is 
not the original author of the code defining the enum.  (Often the person 
downloading and using a package from PyPI has less advanced Python knowledge 
than the pa
 ckage author, so they may have a hard time debugging the situation.)

You can see how having the getframe hack in place makes life more pleasant for 
many people -- the package user won't have to debug the pickling problem, and 
the package author won't have to deal with the bug report and fix.

But what about other Python implementations?  Well, TBH, they have plenty of 
other issues.  The reality is that you can't take a large package that hasn't 
been tested on Jython, or IronPython, or PyPy, and expect it to just work on 
any of those.  Sure, things are getting better.  But there are still tons of 
differences between the various Python implementations (as there are between 
different versions of CPython), and whether you like it or not, CPython is 
still the Python version of choice for most people.  The long and short of it 
is that porting any significant package to another implementation is a bit of 
work, and keeping the port working probably requires adding some set of 
additional line items to the style guide used by its developers -- don't use 
feature X, don't depend on behavior Y, always use pattern Z...


However, I don't expect that "always pass module=__name__ when using the enum 
convenience API" won't have to be added to that list.  sys._getframe() is way 
more powerful than what's needed.  Even on platforms where sys._getframe() is 
unimplementable (or disabled by default in favor of a 10% speedup), it should 
still be possible to provide an API that *just* gets the module name of the 
caller, at least in case the call site is top-level module code (and for 
anything else, the getframe hack doesn't work anyway).  After all, we're 
talking about a full Python implementation, right?  That's a dynamic language 
with lots of introspection APIs, and any implementation worth its salt will 
have to deal with that, even if full-fledged sys._getframe() is explicitly 
excluded.

So I propose that we use sys._getframe() for the time being, and the authors of 
Jython, IronPython and PyPy can get together and figure out how to implement 
something like sys.get_calling_module_name().  They have plenty of time -- at 
least until they pledge support for Python 3.4.  To make it easy for them we 
should probably add that API to CPython 3.4.  And it's fine with me if the 
function only works if the caller is top-level code in a module.

Which reminds me.  Nick offered another use case where using sys._getframe() 
breaks down: a wrapper function that constructs an enum for its caller.  First 
of all, I think this is a pretty rare use case.  But additionally, that wrapper 
could just use sys.get_calling_module_name(), and everything would be fine.

PS. Whoever adds sys.get_calling_module_name() to CPython, please pick a 
shorter name. :-)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue17947>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to