kalekundert / autoclasstoc

Sphinx plugin to make easier-to-navigate class documentation.
MIT License
18 stars 7 forks source link

Advice on categorizing class members? #3

Closed funkyfuture closed 4 years ago

funkyfuture commented 4 years ago

could you give some advice how one could explicitly categorize methods (and possibly properties)?

from the annotator's perspective a decorator that adds an attribute to the method would be simple, e.g. like

def category(name: str):
    def annotator(method):
        method.__category__ = name
        return method
    return annotator

yet, how would the __category__ property be accessible from a predicate method? also, this would only be usable with methods, not properties.

another option might be to use the meta field in a docstring. but i haven't looked into its exact intended uses and limitations. another idea might be to use dedicated fields (e.g. category). but again, i didn't dig deeper yet.

i'd appreciate your feedback in order to proceed, including creating needed patches for the extension.

kalekundert commented 4 years ago

I haven't tested this, but I think __category__ should be easily accessible from predicate():

from autoclasstoc import Section

class MySection(Section):
    key = 'my-section'
    title = 'My Section:'

    def predicate(self, name, attr):
        return getattr(attr, '__category__', None) == 'section value'

In terms of categorizing non-methods, both the approaches you outlined (parse the docstring, or read a devoted class-wide attribute) would work. Parsing the docstring would probably be more work, but would also be more sanitary in the sense that it wouldn't require changing the class. You might be able to get sphinx/docutils to do the parsing for you, see autoclasstoc.utils.nodes_from_rst().

For my applications, I've been able to categorize attributes based on their names, e.g. anything that begins with "on_" is an event handler (I think I put that example in the docs). But of course that's not necessarily an option for you.

You could also keep a mapping of attribute names to categories in conf.py, and refer to that in your Section class. That would be another way to keep from having to change anything about the code, with the obvious disadvantage that it would be harder to maintain.

It depends on what you're trying to do, but I think my instinct would be to parse the docstring. Maybe it would be worth adding a utility function to autoclasstoc that can parse a docstring and extract :meta: fields.

kalekundert commented 4 years ago

Update: sphinx already has a function that can extract metadata from a docstring, so there's no need for me to add something similar to autoclasstoc:

>>> from sphinx.util.docstrings import extract_metadata
>>> doc = """\
... Hello world
... 
... :meta category: foo
... """
>>> extract_metadata(doc)
{'category': 'foo'}

I will add an example of this to the documentation, though. This extract_metadata() function isn't exactly easy to find. Maybe also a builtin section that uses it...

funkyfuture commented 4 years ago

thanks for your input.

actually, i probably misread the attr as attrs and hence had the idea that these would be all class attributes (and got a little confused about it).

what about this signature, that would make that imo clearer and also incorporate the meta fields (to shorten extract_metadata(attr.__doc__))?

class MySection(Section):
    def predicate(self, name, member, doc_meta_fields):
        ...

i don't know how often the latter would be used, but it would encourage using it.

kalekundert commented 4 years ago

I like the idea of providing the meta fields as an argument. These fields are an established idiom for autodoc, so I think it's good to encourage their use.

I'm going to leave the attr argument the same. This goes back to what we've been discussing in #2, except this time I'm actually using the term "attribute" correctly, haha. Plus, you can use whatever signature you want in your subclasses.

funkyfuture commented 4 years ago

okay, shall i look into implementing it?

kalekundert commented 4 years ago

No worries, just did it. Let me know if you find any issues, though.