Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make Python/Sphinx document object attributes only declared in __init__?

I have Python classes with object attributes which are only declared as part of running the constructor, like so:

class Foo(object):
    def __init__(self, base):
        self.basepath = base

        temp = []
        for run in os.listdir(self.basepath):
            if self.foo(run):
                temp.append(run)
        self.availableruns = tuple(sorted(temp))

If I now use either help(Foo) or attempt to document Foo in Sphinx, the self.basepath and self.availableruns attributes are not shown. That's a problem for users of our API.

I've tried searching for a standard way to ensure that these "dynamically declared" attributes can be found (and preferably docstring'd) by the parser, but no luck so far. Any suggestions? Thanks.

like image 643
andybuckley Avatar asked Oct 18 '10 13:10

andybuckley


2 Answers

I've tried searching for a standard way to ensure that these "dynamically declared" attributes can be found (and preferably docstring'd) by the parser, but no luck so far. Any suggestions?

They cannot ever be "detected" by any parser.

Python has setattr. The complete set of attributes is never "detectable", in any sense of the word.

You absolutely must describe them in the docstring.

[Unless you want to do a bunch of meta-programming to generate docstrings from stuff you gathered from inspect or something. Even then, your "solution" would be incomplete as soon as you starting using setattr.]

class Foo(object):
    """
    :ivar basepath:
    :ivar availableruns:
    """
    def __init__(self, base):
like image 185
S.Lott Avatar answered Oct 16 '22 07:10

S.Lott


You could define a class variable with the same name as the instance variable. That class variable will then be shadowed by the instance variable when you set it. E.g:

class Foo(object):
    #: Doc comment for availableruns
    availableruns = ()

    def __init__(self, base):
        ...
        self.availableruns = tuple(sorted(temp))

Indeed, if the instance variable has a useful immutable default value (eg None or the empty tuple), then you can save a little memory by just not setting the variable if should have its default value. Of course, this approach won't work if you're talking about an instance variable that you might want to delete (e.g., del foo.availableruns)-- but I find that's not a very common case.

If you're using sphinx, and have "autoattribute" set, then this should get documented appropriately. Or, depending on the context of what you're doing, you could just directly use the Sphinx .. py:attribute:: directive.

like image 42
Edward Loper Avatar answered Oct 16 '22 08:10

Edward Loper