Re: h(re) for help, import re - on NameError

2016-09-23 Thread Chris Angelico
On Fri, Sep 23, 2016 at 4:40 PM, Peter Otten <__pete...@web.de> wrote:
> By the way, the current help() already loads a module if you pass its name
> as a string:
>

Yes, which is the basis of my alternate exec trick:

exec(tb.tb_frame.f_code, tb.tb_frame.f_globals, {n: n})

Basically it creates a new locals dict that just has (eg) re="re",
which allows help(re) to function as help("re").

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


Re: h(re) for help, import re - on NameError

2016-09-22 Thread Peter Otten
Veek M wrote:

> Is there a way to use .pythonrc.py to provide a help function that
> autoloads whatever module name is passed like so:

By the way, the current help() already loads a module if you pass its name 
as a string:

$ echo 'print("importing foo")' >  foo.py
$ python3
Python 3.4.3 (default, Sep 14 2016, 12:36:27) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> help("foo")
importing foo
Help on module foo:

NAME
foo

[snip]


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


Re: h(re) for help, import re - on NameError

2016-09-22 Thread Veek M
Chris Angelico wrote:

> On Thu, Sep 22, 2016 at 8:10 PM, Veek M  wrote:
>> Is there a way to use .pythonrc.py to provide a help function that
>> autoloads whatever module name is passed like so:
>> \>>> h(re)
>>
>> I tried inheriting site._Helper and overriding __init__ and __call__
>> but that didn't work, also I don't know how to deal/trap/catch the
>> NameError (no quotes on h(re)) - is there a way to insert a
>> try/except block around the >>> prompt?
>>
>> I hate having to: import whatever every-time i forget. Actually could
>> I ditch the () in h(re) and just do: h re - the joy of that :p
> 
> You could use sys.excepthook to catch the NameError. I don't know of a
> way to catch the SyntaxError and look at the original text, but with
> NameError it's pretty easy:
> 
> def excepthook(t,v,tb):
> if t is NameError:
> n = v.args[0].split("'")[1]
> globals()[n] = __import__(n)
> exec(tb.tb_frame.f_code, tb.tb_frame.f_globals)
> else:
> excepthook.old(t,v,tb)
> 
> import sys
> excepthook.old = sys.excepthook
> sys.excepthook = excepthook
> 
> Paste that into interactive Python and give it a try. Be aware that
> it'll attempt to import *any* dud name, so it'll potentially slow
> stuff down any time you typo. Also, it re-executes the current
> traceback frame, which may or may not be appropriate; it's fine for
> help(re), but not otherwise.
> 
> As an alternative, you could inspect tb.tb_frame.f_code to see if it
> matches "help(x)", and if it does, simply re-execute it with the
> string form of the name:
> 
> exec(tb.tb_frame.f_code, tb.tb_frame.f_globals, {n: n})
> 
> This works because help('re') does the same thing as help(re), so by
> effectively setting re="re", you gain that functionality without
> actually importing into the global namespace.
> 
> Adequately recognizing help(re) without false positives is left as an
> exercise for the reader. :)
> 
> ChrisA

works great :) - okay so you save and replace the default exception 
handler for the interpreter. Then when the procedure is called, check to 
see if type is NameError - if yes, then value contains the error string 
with module name, so you split and extract module name, and import the 
module and map it to a name in the global NS and hey presto (run the old 
code with the modified NS - that's a bit funky)!

Regarding fiddling with the code-object, yep, 
tb.tb_frame.f_code.co_names has a tuple ('h', 're') I suppose that's 
clean because it's your input after all vs splitting on something system 
generated (like an error message) 

works brilliantly - thanks :)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: h(re) for help, import re - on NameError

2016-09-22 Thread Chris Angelico
On Thu, Sep 22, 2016 at 8:10 PM, Veek M  wrote:
> Is there a way to use .pythonrc.py to provide a help function that
> autoloads whatever module name is passed like so:
> \>>> h(re)
>
> I tried inheriting site._Helper and overriding __init__ and __call__ but
> that didn't work, also I don't know how to deal/trap/catch the NameError
> (no quotes on h(re)) - is there a way to insert a try/except block
> around the >>> prompt?
>
> I hate having to: import whatever every-time i forget. Actually could I
> ditch the () in h(re) and just do: h re - the joy of that :p

You could use sys.excepthook to catch the NameError. I don't know of a
way to catch the SyntaxError and look at the original text, but with
NameError it's pretty easy:

def excepthook(t,v,tb):
if t is NameError:
n = v.args[0].split("'")[1]
globals()[n] = __import__(n)
exec(tb.tb_frame.f_code, tb.tb_frame.f_globals)
else:
excepthook.old(t,v,tb)

import sys
excepthook.old = sys.excepthook
sys.excepthook = excepthook

Paste that into interactive Python and give it a try. Be aware that
it'll attempt to import *any* dud name, so it'll potentially slow
stuff down any time you typo. Also, it re-executes the current
traceback frame, which may or may not be appropriate; it's fine for
help(re), but not otherwise.

As an alternative, you could inspect tb.tb_frame.f_code to see if it
matches "help(x)", and if it does, simply re-execute it with the
string form of the name:

exec(tb.tb_frame.f_code, tb.tb_frame.f_globals, {n: n})

This works because help('re') does the same thing as help(re), so by
effectively setting re="re", you gain that functionality without
actually importing into the global namespace.

Adequately recognizing help(re) without false positives is left as an
exercise for the reader. :)

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