attrs
attrs copied to clipboard
Self documentation - current state
@hynek @chadrik
I've tried following this and other threads and reading the current docs, but can't see if/how one best produces any documentation directly from the attr.ib()
definitions.
If it does not exist, would something like argparse
be a good example?
I suppose the type annotation (e.g. using attr.s(auto_attribs=True)
is a step in the direction I am thinking/hoping for. I don't know the details, but Emacs does a good job of self-documenting, which is especially useful with the type annotation, as that provides at least some information for each argument.
Could someone point me in the right direction, please?
I am also looking at a way to produce documentation, possibly in some json-schema format for my JSON serialization of attrs objects.
The key for me is honing on a proper way to add a description or help or doc to an attribute as per @manishtomar in #104 and also to an object (and eventually to nested objects like in @Tinche cattrs) .
This could use metadata alright for attr.ib
, but at least there should be a convention that we can all agree for this?
From then I could introspect my objects to generate some docs.
Another helper to me would be @toumorokoshi jsonschema-extractor most likely. It does not handle any doc/help/description though.
I'd be up for adding functionality into jsonschema-extractor to extract docstring data. I like the example of:
@attr.s
class Foo:
x = attr.ib(doc="this is a variable")
It might be nice to collect the use cases for this feature before start talking API?
As one of the use case for me, I maintain this tool https://github.com/nexB/scancode-toolkit. At a high level the tool returns structured data in a file (formatted as JSON): the format needs to be properly documented. This documentation could include generated json schema(s).
Internally, this is for now a messy mish-mash of plain objects, plain data structures, namedtuples, attr objects and schematics objects. I would like to move it all to attr and have a not too complicated path to generate sphynx doc, custom docs and json-schema.
Having a description attached to a field or object is quite important for any documentation to be meaningful to me.
@manishtomar @Nicholas-Mitchell any more input so we can make this move forward?
I would like to move it all to attr and have a not too complicated path to generate sphynx doc
@pombredanne My original intent was exactly this. Also it makes the code more readable.
Interface-wise, added a doc
argument to the attribute definition would be a clean and simple way to add the functionality on the front-end, leaving and clever parts behind the scenes, perhaps controlled by other keyword arguments argument, e.g. x = attr.ib(doc='a variable of some kind
, **kwargs)-->
x = attr.ib(doc='a variable of some kind, doc_backend='sphynx')
, etc.
Perhaps the following will inherently be covered by a Sphynx-type solution, but I will mention it just in case it sparks other ideas.
Another type of functionality in which I am most interested is interactive use of the documentation; usually via docstrings in either (1) the interactive prompt, (2) a Jupyter notebook or (3) an IDE. I do this extensively whilst coding, preferring that to finding leaving eh coding environment to find a website with the docs.
As I integrate attrs
, I am still writing the docstrings myself (this follows the general concentions of NumPy):
class NormalClass:
"""An class that uses attrs to do interesting stuff.
Parameters
----------
x : {int, float}
a vector - some more useful information
"""
def __init__(self, x):
self.x = x
if not isinstance(x, (int, float)):
# raise an error
This could become:
@attr.s
def AttrsClass:
"""An class that uses attrs to do interesting stuff.
"""
x = attr.ib(default=None, validator=attr.validators.instance_of((int, float)),
doc='a vector - some more useful information')
Then I would end up doing something like this is in an ipython prompt: AttrsClass?
in order to read the documentation.
a = AttrsClass(x=23.5)
# Have a look at the docstring for the class
a?
This could then be extended, using the suggested approach of a doc
argument, to work like this for individual attributes:
a.x.doc
# Even perhaps using the ipython helper: ?
a.x?
Current functionality of the last line would show information about the type
of x (in this case an int).
Maybe these things could be incorporated into the __repr__
functions somehow, so the new doc
info is nicely printed with the class.
So for extracting information by other tools, you can already use metadata={"doc": "whatever"}
so I think the really interesting part here is the expansion of the class’ __doc__
.
For those who really want that right now, I’m pretty sure you can build yourself a decorator that does the same thing and patches the class’ __doc__
.
The open questions are:
- where will the type information come from (I’m gonna say
type
since it can be set both using annotations andattr.ib(type=x)
. - how is
__doc__
supposed to be formatted?
2 Seems more complicated than it sounds and I’m not 100% confident we can achieve a solution that is good for everyone. 🤔 Most flexible idea from the top of my head would be to allow for a {attrs_ivar_docs}
I suppose?
@hynek: agreed. Perhaps attr.s
could take a doc_formatter
argument which is an object of a given shape that can generate the documentation for attributes? Then one could eventually write formatters for different styles?
All seem like good ideas, @hynek @wsanchez
Your suggested doc-formatter
argument to attr.s
could also just be an option from a (probably short) list of available common formatting styles. So the actual implementation of a formatter wouldn't be left to the user without at least offering something that just works. This would mean the user must then write docstrings that correspond to the available formatters, but as attrs is generally about making life easier, I find that a nice trade-off.
Any news on this one?
Perhaps a Sphinx extension could pull attributes off the attr.fields(cls)
to help with the formatting for API docs. Of course, that doesn't address help(cls)
.
Note that https://docs.python.org/3/whatsnew/3.8.html#inspect allows __slots__
to now have documentation in Python 3.8 (you make it a dict). This might be quite useful for a doc=
on an attribute of a slots class (where this currently would be a bit more challenging to do).
Example:
class A:
__slots__ = {"one": "one doc"}
help(A.one)
Python 3.7:
Help on member descriptor __main__.A.one:
one
Python 3.8:
Help on member descriptor __main__.A.one:
one
one doc
One use case I would like in attrs (although that might make more sense as a plugin than as part of the core) is to have an independent JSON Schema (or Ion, or protobuf, or whatever) defining the structure, and then be able to construct an attrs class from it automatically -- essentially an attrs-based equivalent of warlock.
I don't think there is one format of __doc__
that is good for everyone. Some people are only interested in Sphinx format while some find it too ugly and want something easier to read like Google's. It's obvious to me that attrs should keep doc string of class and attributes and any related metadata in a dict of some sort. And then users can provide a DocFormatter to write the doc string that they desire.
My use case is to write doc string once for individual attributes and then programmatically display them in command-line arguments and also to generate Sphinx documentation.
🤔 maybe typing.Annotated
can be useful here? https://docs.python.org/3/library/typing.html#typing.Annotated
it would basically move the problem outside the attrs
api altogether:
attrs.define
class A:
b: Annotated[str, "b for 🍌"]
c: Annotated[str, "c is for 🍪, of course!"]