AlexandreDecan / portion

portion, a Python library providing data structure and operations for intervals.
GNU Lesser General Public License v3.0
476 stars 34 forks source link

Permit setting the docstring of an Interval #67

Closed ChrisSantosLang closed 3 years ago

ChrisSantosLang commented 3 years ago

I define a constant like this:

ALL = P.open(-P.inf, P.inf)

Now I would like to attach a docstring to explain how the constant is to be used:

ALL.__doc__ = "A shortcut for the portion.interval.Interval that contains all"

...but this gives me the error AttributeError: 'Interval' object attribute '__doc__' is read-only

AlexandreDecan commented 3 years ago

Hello (and FYI, that is the usual way to start a discussion),

What is the exactly the question?

For what I understood, it seems you want to associate specific documentation to a single object. That's not how Python works: documentation is attached to a class, not to objects. That's definitely not something specific to portion...

ChrisSantosLang commented 3 years ago

Hello (and I really like your work)

Sphinx has an autodata directive, so I'm not the first person to think constants (and other data) should have their own documentation defined in the code. For my constant, however, this directive is displaying the generic docstring for Interval (i.e. inherited from the class). My IDE is not displaying the docstring (although maybe it should), so I guess I can just avoid using the autodata directive.

setting ALL.__doc__ might not be the right way to set individual docstrings, but each Interval could have its own docstring, just like it can have its own values for other properties. I don't want to suggest a specific API because I think you are the better API designer (I love your repr()!).

...just trying to be helpful here (you've contributed so much, and giving feedback is the least I can do in return)...

AlexandreDecan commented 3 years ago

Hi,

Thanks for the clarification (and the kind words my ego appreciates :-D) ;)

Honestly, I've no idea on how to define an individual doc for an object. I don't think it's the right way to do (if a specific instance should have a specific documentation, perhaps it should be a kind of constants, through Enum.enum, but even this class does not allow to specify the docstring of an individual object). I get why this could be interesting for some intervals, though.

One possibility could be to subclass Interval:

>>> class AllInterval(P.Interval):
>>>     """ Documentation for ALL"
>>>     def __init__(self):
>>>         super().__init__(P.open(-P.inf, P.inf))
>>>
>>> ALL = AllInterval()

I haven't tested this piece of code, but it gives the idea ;-)

ChrisSantosLang commented 3 years ago

Thanks! If the IDE I am recommending to developers showed the docstring, then that is what I would do (or subclass Interval, and add a method to set __doc__, or set it in the __init__). It shows other docstrings in a very prominent way, so relevant docstrings become important...

The following works, so I thought you did something special to make it break when substituting Interval() for X():

>>> class X(): pass
>>> y = X()
>>> z = X()
>>> y.__doc__ = "test y"
>>> z.__doc__ = "test z"
>>> X.__doc__ = "test X"
>>> y.__doc__
'test y'
AlexandreDecan commented 3 years ago

The reason likely stems from our definition of __slots__, preventing the documentation to be added/modified on-the-fly. AFAIK, there is nothing we can do to circumvent the read-only behaviour of __doc__ in that case.

Notice though that I still believe that __doc__ shouldn't be "instance-specific". Docstrings are for callables, classes, and methods, not for individual instances. Any workaround you can find to attach specific documentation to instances (as the one you suggested in your comment) is, erh, a workaround, and you cannot expect it to work in some situations simply because it's not expected to be used that way (e.g., pydoc will ignore it since it uses the docstring of the class, not of the instance). I don't know about sphinx, but my guess is that it won't capture the correct docstring as well (unless autodoc is used).

If an object is specific enough (w.r.t. to its class) to get a specific documentation, then I would definitely consider wrapping it in an Enum (see aenum project on PyPI, it seems there is some support to add documentation on enumerated items), or create a subclass as I suggested, or even in a function:

def ALL():
   """ A shortcut for the portion.interval.Interval that contains all. """
   return P.open(-Pinf, P.inf)

To some extent, this is in line with our P.empty() function returning the "special" empty interval...

ChrisSantosLang commented 3 years ago

That's a great suggestion for how to get my IDE (and other IDEs) to show the docstring I want. Thanks!