IPython custom tab-completion for user magic function - python

In IPython, it is fairly easy to provide tab-completion for user-defined object: simply define a __dir__ method that returns a list of strings to the object.
IPython also provide us with a way to define our own custom magic functions using the handy register_line_magic utility. In some ~/.ipython/profile_default/startup/magictest.py:
from IPython.core.magic import register_line_magic
#register_line_magic
def show(dataType):
# do something depending on the given `dataType` value
Now my question is: how to provide auto-completion to this magic function?
According to this email, one should look into IPython.core.interactiveshell.InteractiveShell.init_completer() for an example of magic function completers such as %reset, '%cd', etc...
However, in the same startup file as the one in which my magic function is defined, the following code didn't work:
from IPython.core.interactiveshell import InteractiveShell
def show_complete():
return ['dbs', 'databases', 'collections']
InteractiveShell._instance.set_hook(
'complete_command', show_complete, str_key='%show')
In the IPython shell, typing %show TAB triggers nothing (print statements in the function show that the function is not even called).
Could somebody point me out on some documentation or examples on how to define such user-magic command parameters completion from within the Ipython startup files?
Thanks!

You can use this:
def load_ipython_extension(ipython):
def apt_completers(self, event):
""" This should return a list of strings with possible completions.
Note that all the included strings that don't start with event.symbol
are removed, in order to not confuse readline.
"""
return ['update', 'upgrade', 'install', 'remove']
ipython.set_hook('complete_command', apt_completers, re_key = '%%apt')
%%apt is the magic keyword

Related

Checking arguments of a function in ipython

I'm using the jupyter ipython notebook by anaconda.
IS there a quick way of looking at the arguments of a function like we do in RStudio? For e.g. ?merge displays documentation for merge in the lower right window of RStudio.
I was specifically looking for arguments of matplotlib.figure() which I found here but this is time consuming: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figure
Found this post related to the question: Getting list of parameter names inside python function
but not sure if it is the same question.
You can try help(matplotlib.figure) after importing matplotlib
Type matplotlib.figure? at the command prompt, and it'll give you the signature and documentation:
In [1]: import matplotlib
In [2]: matplotlib.figure?
Type: module
String form: <module 'matplotlib.figure' from '~/venv/lib/python2.7/site-packages/matplotlib/figure.pyc'>
File: ~/venv/lib/python2.7/site-packages/matplotlib/figure.py
Docstring:
The figure module provides the top-level
:class:`~matplotlib.artist.Artist`, the :class:`Figure`, which
contains all the plot elements. The following classes are defined
:class:`SubplotParams`
control the default spacing of the subplots
:class:`Figure`
top level container for all plot elements
From the IPython introduction:
Exploring your objects
Typing object_name? will print all sorts of details about any object, including docstrings, function definition lines (for call arguments) and constructor details for classes. To get specific information on an object, you can use the magic commands %pdoc, %pdef, %psource and %pfile
You can also use the standard Python help() function; the output is a little more verbose and not coloured, like the ipython object? command however.

Most Pythonic way to provide function metadata at compile time?

I am building a very basic platform in the form of a Python 2.7 module. This module has a read-eval-print loop where entered user commands are mapped to function calls. Since I am trying to make it easy to build plugin modules for my platform, the function calls will be from my Main module to an arbitrary plugin module. I'd like a plugin builder to be able to specify the command that he wants to trigger his function, so I've been looking for a Pythonic way to remotely enter a mapping in the command->function dict in the Main module from the plugin module.
I've looked at several things:
Method name parsing: the Main module would import the plugin module
and scan it for method names that match a certain format. For
example, it might add the download_file_command(file) method to its
dict as "download file" -> download_file_command. However, getting a
concise, easy-to-type command name (say, "dl") requires that the
function's name also be short, which isn't good for code
readability. It also requires the plugin developer to conform to a
precise naming format.
Cross-module decorators: decorators would let
the plugin developer name his function whatever he wants and simply
add something like #Main.register("dl"), but they would necessarily
require that I both modify another module's namespace and keep
global state in the Main module. I understand this is very bad.
Same-module decorators: using the same logic as above, I could add a
decorator that adds the function's name to some command name->function mapping local to the
plugin module and retrieve the mapping to the Main module with an
API call. This requires that certain methods always be present or
inherited though, and - if my understanding of decorators is correct - the function will only register itself the first time it is run and will unnecessarily re-register itself every subsequent time
thereafter.
Thus, what I really need is a Pythonic way to annotate a function with the command name that should trigger it, and that way can't be the function's name. I need to be able to extract the command name->function mapping when I import the module, and any less work on the plugin developer's side is a big plus.
Thanks for the help, and my apologies if there are any flaws in my Python understanding; I'm relatively new to the language.
Building or Standing on the first part of #ericstalbot's answer, you might find it convenient to use a decorator like the following.
################################################################################
import functools
def register(command_name):
def wrapped(fn):
#functools.wraps(fn)
def wrapped_f(*args, **kwargs):
return fn(*args, **kwargs)
wrapped_f.__doc__ += "(command=%s)" % command_name
wrapped_f.command_name = command_name
return wrapped_f
return wrapped
################################################################################
#register('cp')
def copy_all_the_files(*args, **kwargs):
"""Copy many files."""
print "copy_all_the_files:", args, kwargs
################################################################################
print "Command Name: ", copy_all_the_files.command_name
print "Docstring : ", copy_all_the_files.__doc__
copy_all_the_files("a", "b", keep=True)
Output when run:
Command Name: cp
Docstring : Copy many files.(command=cp)
copy_all_the_files: ('a', 'b') {'keep': True}
User-defined functions can have arbitrary attributes. So you could specify that plug-in functions have an attribute with a certain name. For example:
def a():
return 1
a.command_name = 'get_one'
Then, in your module you could build a mapping like this:
import inspect #from standard library
import plugin
mapping = {}
for v in plugin.__dict__.itervalues():
if inspect.isfunction(v) and v.hasattr('command_name'):
mapping[v.command_name] = v
To read about arbitrary attributes for user-defined functions see the docs
There are two parts in a plugin system:
Discover plugins
Trigger some code execution in a plugin
The proposed solutions in your question address only the second part.
There many ways to implement both depending on your requirements e.g., to enable plugins, they could be specified in a configuration file for your application:
plugins = some_package.plugin_for_your_app
another_plugin_module
# ...
To implement loading of the plugin modules:
plugins = [importlib.import_module(name) for name in config.get("plugins")]
To get a dictionary: command name -> function:
commands = {name: func
for plugin in plugins
for name, func in plugin.get_commands().items()}
Plugin author can use any method to implement get_commands() e.g., using prefixes or decorators — your main application shouldn't care as long as get_commands() returns the command dictionary for each plugin.
For example, some_plugin.py (full source):
def f(a, b):
return a + b
def get_commands():
return {"add": f, "multiply": lambda x,y: x*y}
It defines two commands add, multiply.

Python dir command to determine the methods

I am using Python's dir() function to determine what attributes and methods a class has.
For example to determine the methods in wx.Frame, I use dir(wx.Frame)
Is there any command to determine the list of arguments for each method? For example, if I want to know what arguments belong to wx.Frame.CreateToolBar().
As mentioned in the comments, you can use help(fun) to enter the help editor with the function's signature and docstring. You can also simply use print fun.__doc__ and for most mature libraries you should get reasonable documentation about the parameters and the function signature.
If you're talking about interactive help, consider using IPython which has some useful extras. For instance you could type %psource fun to get a printout of the source code for the function fun, and with tab completion you could just type wx.Frame. and then hit TAB to see a list of all of the methods and attributes available within wx.Frame.
Even though GP89 seems to have already answered this question, I thought I'd jump in with a little more detail.
First, GP89's suggestion was the use Python's built-in help() method. This is a method you can use in the interactive console. For methods, it will print the method's declaration line along with the class' docstring, if it is defined. You can also access this with <object>.__doc__ For example:
>>> def testHelp(arg1, arg2=0):
... """This is the docstring that will print when you
... call help(testHelp). testHelp.__doc__ will also
... return this string. Here is where you should
... describe your method and all its arguments."""
...
>>> help(testHelp)
Help on function testHelp in module __main__:
testHelp(arg1, arg2=0)
This is the docstring that will print when you
call help(testHelp). testHelp.__doc__ will also
return this string. Here is where you should
describe your method and all its arguments.
>>>
However, another extremely important tool for understanding methods, classes and functions is the toolkit's API. For built-in Python functions, you should check the Python Doc Library. That's where I found the documentation for the help() function. You're using wxPython, whose API can be found here, so a quick search for "wx.Frame api" and you can find this page describing all of wx.Frame's methods and variables. Unfortunately, CreatteToolBar() isn't particularly well documented but you can still see it's arguments:
CreateToolBar(self, style, winid, name)
Happy coding!

Set defaults at runtime

I manage a fairly large python-based quantum chemistry suite, PyQuante. I'm currently struggling with how to set various defaults so that users can choose among different options at runtime.
For example, I have three different methods for computing electron repulsion integrals. Let's call them a,b,c. I used to simply pick the one I liked best (say, c), and have that hard-wired into the module that computes these integrals.
I have now modified this to use a module, Defaults.py, that contains all such hard-wires. But this is set at compile/install time. I would now like users to be able to override these options at runtime, say, using a .pyquanterc.py file.
In my integral routines, I currently have something like
from Defaults import integral_method
I know about dictionaries, and the .update() method. But I don't know how I would use this in real life. My defaults module looks like
integral_method = c
should I modify the end of Defaults.py to look for a .pythonrc.py file and override these values? E.g.
if os.path.exists('$HOME/.pythonrc.py'): do_something
If so, what should do_something look like?
With your current setup, the user can change the default functions in his scripts quite easily:
import Defaults
Defaults.integral_method = somefunc
If the user adds this to his script, all your modules that use integral_method from Defaults will use somefunc to calculate integrals.
I might do this via a factory class.
class IntegralSolver:
"""
Factory class containing methods for solving integrals.
>>> solver = IntegralSolver("method1")
>>> solver(x)
# solution via method1
Can also be used directly:
>>> IntegralSolver.method2(x)
# solution via method2
"""
def __init__(self, method):
self.__call__ = getattr(self, method)
#staticmethod
def method1(x):
return method1_solution
#staticmethod
def method2(x):
return method2_solution
It really depends on how your user runs the toolset. If they twiddle the python code each time, just setting a block at the top labeled OPTIONS should be good. If they run it off the command line, use the argparse library to allow them to switch options on the command line. Perhaps have it read the options out of a file with configParser to read a default file with your options, and if the user sets it, an additional file with their options.

How to get PyCharm to auto-complete code in methods?

When I'm using a 3rd party l
ibrary such as boto, PyCharm seems to be able to auto-complete quite nicely
However, as soon as I define a function of my own, auto-complete breaks down inside that function. I understand why, since I can't give the function any type information about its arguments, so it can't guess how to auto-complete. Is there a way around this issue?
Edit
I tried using the docstring (for Python 2), but still no auto-complete
def delete_oldest_backups(conn, backups_to_keep, backup_description):
"""
delete_oldest_backups(EC2Connection, int, string)
"""
(Also tried boto.ec2.connection.EC2Connection instead of just EC2Connection)
You can use type hints: http://www.jetbrains.com/pycharm/webhelp/type-hinting-in-pycharm.html
def some_method(self, conn):
"""
#type conn: EC2Connection
"""
conn.<autocomplete>
You can specify the type information about the parameters of the function using Python 3 parameter and return value annotations. If you're using Python 2, you can also specify information in the function's docstring. PyCharm understands the format used by docstrings of binary modules in the standard library, for example:
"""
foo(int, string) -> list
Returns the list of something
"""
In order for PyCharm to recognize an instance of an object and retrieve all its methods, we have to use the following statements. But I think that both is a terrible way of wasting programming and run time.
assert isinstance(instanceX, ClassOfInstanceX)
instanceX.{#list of method/properties appears}
Alternatively, you can also use the class name will recall the method or property everytime you want to invoke it and pass in the instance to the self parameter. But this is too verbose, for my liking, esp for nested class
ClassOfInstanceX.{#list of method/properties appears}
# then you will have...
ClassOfInstance.method(instanceX, args...)
You can install the library via pyCharm "package manager".
Go to Settings -> Project Interpreter -> Python Interpreters
And in the Packages list, click on install and search for the library you want to install
Once installed, auto-complete will be available on editor.
Hope this is what you are looking for.

Categories