classification
Title: Deprecate the frame hack for implicitly getting module details
Type: enhancement Stage:
Components: Versions: Python 3.4
process
Status: open Resolution:
Dependencies: 17941 Superseder:
Assigned To: Nosy List: brett.cannon, eli.bendersky, eric.snow, gvanrossum, haypo, ncoghlan, rhettinger
Priority: normal Keywords:

Created on 2013-05-12 13:09 by ncoghlan, last changed 2015-07-21 07:34 by ethan.furman.

Messages (9)
msg189028 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2013-05-12 13:09
(Split off from issue 17947)

collections.namedtuple includes a frame hack that attempts to make the functional API work for ordinary module level assignments:

    try:
        result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
    except (AttributeError, ValueError):
        pass


I *really* don't like the fact that this hack is being incorporated into the PEP 435 implementation as well, when that API has been designed to include an explicit cross-implementation workaround for this case.

Eli asked me to move the discussion over to a new issue to allow the implementation issue to focus on incorporating the PEP as is.

Issue 17941 (the explicit module keyword-only argument) suggest incorporating PEP 435's robust, cross-implementation way to support pickling in the functional API into collection namedtuple as well, suggesting to me that the frame hack should be deprecated, not propagated further.

The main reason I don't like it is not the fact it doesn't work reliably on other implementations, but the fact it doesn't work reliably in CPython either - if you create a helper function, then the frame hack will pick up the module where the helper function lives rather than where you ultimately store the created object. Without some explicit way of telling the created object the final destination (whether through an argument or through new syntax and a name binding protocol), I don't see a way to resolve this dilemna in a robust way.

However, Guido tells me that he really wants to keep the frame hack (and include it for PEP 435 as well), so this issue is basically about documenting that rationale somewhere.
msg189033 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2013-05-12 13:52
I believe Guido will be happy to replace the frame hack once we have something better, such as a way to implicitly (or explicitly in the case of helper functions) pass the calling  module's name.

Maybe a global __calling_module__ that a function can look at... or something similar, anyway.
msg189034 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2013-05-12 14:06
Right, but I think it's categorically impossible to make that work reliably without new syntax and a name binding protocol (or something equivalent).

Due to the existence of the global keyword, the frame stack and normal assignment syntax simply don't provide adequate information for us to tell the difference between "incidental" assignments in a helper function and "definite assignments" that represent the ultimate destination.

And if the solution involves new syntax, then the frame hack will have to be deprecated at some point anyway.
msg189035 - (view) Author: Nick Coghlan (ncoghlan) * (Python committer) Date: 2013-05-12 14:07
Oops, that was supposed to be "definitive assignments" in my previous comment.
msg189044 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2013-05-12 16:32
If you read the docs for sys._getframe() (http://docs.python.org/3/library/sys.html#sys._getframe) we explicitly state that the function should be considered an implementation detail for CPython. While Nick doesn't want to argue from the VM angle, I will.

I would prefer to not rely on this hack in the stdlib to not put the other VMs at a disadvantage. Nick also has a good point that it is at best a heuristic as you can fool it into using the wrong result.

At minimum I think the keyword argument for the module being used should be provided and documented that if it isn't provided then pickling is wishy-washy based on how you call the function and that it is not cross-VM compatible. But knowing that users won't clearly read the docs if it just happens to work in the interpreter and that is partial luck because of the possible indirection issue Nick pointed out, I think it would be better to not rely upon sys._getframe() and just ask people to explicitly specify the module if they happen to care about pickling *and* are using the functional API for enums.
msg189163 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-05-13 18:37
As I explained in issue 17947, I think that any Python implementation worth its salt should be able to implement sys.get_calling_module_name() (*), at least for the case where the caller is top-level code in a module body.  That is a much weaker requirement than being able to implement sys._getframe().  We should just add this to CPython 3.4 and require that conforming implementations support it, at least in the stated context (top-level caller).

(*) Please pick a somewhat shorter name for it.
msg194319 - (view) Author: Eli Bendersky (eli.bendersky) * (Python committer) Date: 2013-08-04 01:02
I'm (somewhat) back looking at this. Should the first step be sys.get_calling_module_name()? I can provide a patch. Re its name, perhaps the long name isn't that bad given that this is a rather obscure API. But suggestions for something shorter/better will be welcome.
msg236563 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2015-02-25 04:22
Eli, did you ever make any progress with this?  Anything you can post so someone else can run with it if you don't have time?
msg236572 - (view) Author: Eli Bendersky (eli.bendersky) * (Python committer) Date: 2015-02-25 12:54
I don't have time, unfortunately. So other folks can pick this up.

I don't remember if I made any progress on this - will post whatever I have if I find something.
History
Date User Action Args
2015-07-21 07:34:48ethan.furmansetnosy: - ethan.furman
2015-02-25 12:54:48eli.benderskysetmessages: + msg236572
2015-02-25 04:22:45ethan.furmansetmessages: + msg236563
2013-08-04 01:02:49eli.benderskysetmessages: + msg194319
2013-06-11 03:52:10eric.snowsetnosy: + eric.snow
2013-05-13 18:37:03gvanrossumsetassignee: gvanrossum ->
messages: + msg189163
2013-05-13 13:26:40hayposetnosy: + haypo
2013-05-12 16:32:49brett.cannonsetnosy: + brett.cannon
messages: + msg189044
2013-05-12 14:07:13ncoghlansetmessages: + msg189035
2013-05-12 14:06:28ncoghlansetmessages: + msg189034
2013-05-12 13:52:13ethan.furmansetnosy: + ethan.furman
messages: + msg189033
2013-05-12 13:18:01eli.benderskysetnosy: + rhettinger
2013-05-12 13:12:24ncoghlansetdependencies: + namedtuple should support fully qualified name for more portable pickling
2013-05-12 13:09:13ncoghlancreate