1
\$\begingroup\$

Let's say I want to create dynamic documentation of functions I wrote, without using the help() function (I don't want the user to care about arguments accepted by my function, nor get cluttered with other stuff like the copyright info, or other stuff that aren't functions).

Here's an attempt:

import inspect

def foo():
    """Return 'foo' string"""
    return "foo"

def user_defined_functions():
    """Return names of user-defined functions"""
    for name in globals():
        if inspect.isfunction(eval(name)):
            docstring = eval(name + ".__doc__")
            print("{}:\n   {}".format(name, docstring))

And here's the pretty result:

>>> import test
>>> test.user_defined_functions()
user_defined_functions:
   Return names of user-defined functions
foo:
   Return 'foo' string

If I had just used the help function I could have gotten extra stuff I don't need (I'm not writing a library, so the user doesn't need all of this):

Help on module test:

NAME
    test

FUNCTIONS
    foo()
        Return 'foo' string

    user_defined_functions()
        Return names of user-defined functions

FILE
    /home/wena/src/utils/test.py
\$\endgroup\$
2
  • \$\begingroup\$ It's not clear how could you use this function on user defined funtions. The users are going to edit this file? Are you going to import their module? Are you forcing them to import user_defined_function? Would you care to explain better? \$\endgroup\$
    – Rik Poggi
    Mar 9, 2012 at 9:50
  • \$\begingroup\$ I was concerned by the term I chose to use, user-defined-functions, due to a lack of a better one in my head. What I meant by it is functions that aren't built into Python. I am maintaining a CLI application (code.google.com/p/wajig) where there are a bunch of functions in a single file, and each of those represent a subcommand. I need this functionality so that when a user types wajig commands, all functions in that file would get displayed with their docstrings. \$\endgroup\$
    – tshepang
    Mar 9, 2012 at 14:48

2 Answers 2

5
\$\begingroup\$

Use for name, value in globals().items(): then you don't need to use eval

\$\endgroup\$
0
2
\$\begingroup\$

Peeking inside the source code you linked I'd say that what you need is some sort of command table: a dictiony with all the commands and their aliases should do.

To suggest that, other then the fact that you'll need it for what you asked, is that it's almost already written. It's in that ugly if/elif into the help function, but it's almost already there :)

At the beginning of the file:

COMMANDS_TABLE = {"autoalts": ["autoalternatives"],
                  "builddeps": ["builddepend", "builddepends", "builddeps"], 
                  #....

With this table your help function will more or less look like:

def help(args):
    # ...
    for command in in args[1:]:
         for func_name,aliases in COMMANDS_TABLE.items():
             if command in aliases:
                 command = func_name
                 break
         # ...

And your listcommands could be:

def listcommands(args):
    for func_name in sorted(COMMANDS_TABLE):
        print globals()[func_name].__doc__

But this still looks like a hack, and the reason is that a good command table should map the function themselves not their name:

COMMANDS_TABLE = {autoalts: ["autoalternatives"],
                  builddeps: ["builddepend", "builddepends", "builddeps"], 
                  #....

Everything will be a lot easier, because once you get the function, you can ask whatever you want:

def listcommands(args):
    for func in sorted(COMMANDS_TABLE, key=operator.attrgetter('__name__')):
        print func.__doc__

Now, this is a good design! You could later on transform those functions into callables and this code will still work :)

In the source code you linked, there's also a util.help() function, that might need the same kind of changes.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for taking the time to go as far as looking at that ugly code, especially because that was beyond the scope of the original question. \$\endgroup\$
    – tshepang
    Mar 9, 2012 at 18:04
  • \$\begingroup\$ I don't understand the last paragraph: what eats function name and which one is the better choice. \$\endgroup\$
    – tshepang
    Mar 9, 2012 at 18:05
  • \$\begingroup\$ @Tshepang: Oh, I deleted that... Let's continue in chat if you want, because is not strictly related to your question and I took just a quick look at your code, so I wasn't sure. \$\endgroup\$
    – Rik Poggi
    Mar 9, 2012 at 18:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.