-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Variable self ref #13
base: master
Are you sure you want to change the base?
Variable self ref #13
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this, it looks very thorough. I'm not super happy with the name selfref
, but also can't think of any better names.
:meta _:
seems like the right way to go here.
@eric-wieser To be completely honest, I'm not satisfied with the name, either. I definitely do not mind rebasing to change it to a better name. I thought it was better than my original idea of FYI, I'm also working on an implementation of Let me know if you have any requests for changes. Thanks! |
# Priority must be lower than Python domain meta filter to ensure it runs | ||
# before meta info fields are removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does a similar reason force us to not use SphinxTransform
, or did you just switch to 'object-description-transform'
for simplicity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this was the reason I switched away from SphinxTransform
. I couldn't find any mechanism for getting an instance of SphinxTransform
to run before meta
was filtered out. Even setting the default_priority
didn't make it run soon enough. It is entirely possible I just don't know what I'm doing, but I was pretty thorough in looking. I did quite a bit of hooking up events and debugging to see what order things happened in, and I looked through a decent bit of source code trying to find something. (Frankly, the Sphinx source code was too confusing for me to find where transforms are actually applied. I figured out that it's implemented in docutils, which explains why I couldn't find it.) This event was always fired well before the transform was applied, and you can see in the Python domain that this event is where meta
filtering happens. It did seem like a logical place to hook into as well: we're applying a transform on method objects after they get initially parsed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've done some more research on this, and while I could be mistaken because it's difficult to piece together what is invoked where and in what order, my findings seem to confirm that there's not a better way to do this at present.
As noted before, meta
info fields are cleaned on the object-description-transform event. This event occurs when an ObjectDescription
directive is run.
The documentation on Sphinx's core events seems to suggest that SphinxTransform
s added to the application object are run much later than these directives. Specifically, they're run in the same phase as the doctree-read
, which occurs after the document is parsed and directives are executed.
Maybe I should look at implementing a custom info field instead of using meta
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser Sorry for all the messages.
Somewhere along the line in reading more, I stumbled across the pending
element. I figured out how to use this to implement a directive that leaves a sort of "marker" for the transform to process later. It looks like this in usage:
.. py:method:: __await__()
.. selfref:: obj
I also implemented a custom info field (branch is now deleted), which looks like this:
.. method:: __add__(other)
Docstring
:selfref: obj
Both of these implementations preserve the usage of SphinxTransform
. I'm not sure which is more in line with normal docutils/Sphinx patterns. Both feel like they break the mold to me:
pending
was really designed to invoke its own transform, rather than act as a parameter for another one. While I could potentially implement a second transform that goes back and does even more to the signature afterPrettifySpecialMethods
does its work, I felt like that posed a much greater risk of some kind of mistake having an unintended side effect or some particular form of the signature ending up wrong. But I can go back and see about it if you really think I should.- The info fields aren't designed to be parameters for some other transform either. They're supposed to specify additional information about the object being described, except for
meta
which is really only used by autodoc for filtering purposes. I also don't like that the info field gets pre-processed and rendered into another form before our transform processes it. (That's why a call tolower
is required.) I worry that changes to the code that acts on it could somehow break our transform in the future.
It doesn't seem like augmenting an existing directive with additional transforms and parameters is something the system is really designed for, unless I'm missing something.
Anyway, please take a look at both of those implementations and let me know what approach you feel is best going forward. I favor either the meta
info field or the directive with pending
, primarily because I don't like the custom info field getting processed by some other transform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the thorough investigation - I agree, the meta
version seems simplest right now, but feel free to keep looking for better approach if you want to.
Otherwise, I think modulo a little more thought about better words for selfref
, this is good to merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser The more I work with this and consider it, the more I think that a directive is a better choice than an info field, even a meta one. Using a directive lets us avoid hooking into events entirely, avoids potential conflicts with changes to Sphinx's Python domain, and is more semantically correct.
- Directives are the standard mechanism for mark up, and this parameter represents a kind of mark up that changes how the final output is rendered. Info fields provide additional descriptive information about the item being documented, and this is not additional descriptive information.
- The directive also lets us very cleanly segregate our code and elements from everyone else's, making it less likely that some other extension or core function will accidentally process ours incorrectly.
- If we use a meta info field, we're absolutely forced to plug into an event and catch it before the built in event erases it. Even with a non-meta info field, we should use an event to catch it before it gets rewritten.
In a more ideal world, a new option to py:method
would be the most semantically correct, but I don't believe that extending it is a good idea even if it's possible. As far as I can tell, it is not a supported approach, meaning even a working solution is going to be hacky, fragile, and likely to conflict with other extensions trying to do similar tasks.
I suppose the one argument I can think of in favor of an info field is that it looks like an option to the py:method
directive, but I'm not sure that's necessarily a good thing. It requires the user to place whitespace before it if writing reST directly, which is confusing if we want users to think of it as an option.
Do you have any strong objection to using a directive instead?
I'm reverting this to draft. I have an idea that might be more in line with Sphinx's and docutil's intended usage. |
README.rst
Outdated
|
||
.. method:: __add__(other) | ||
Docstring | ||
:meta selfref: obj |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about :meta self-param: obj
, which is remiscent of :param: obj
? Then use self_param
in the python code.
The source of inspect.py
uses self_parameter
, so I think self_param
is a sensible choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eric-wieser I agree that "self param" is a better name. I'm using it in the revision I'm making.
5f42ba5
to
5ee986c
Compare
I'm putting this back into ready state for you to merge if you want. I still believe that the directive based implementation is a big improvement, but if you'd rather stick with the meta parameter, then that's your decision. Let me know if you want to pursue the directive instead. |
A directive seems like the wrong model to me - directives are usually used by a visible block of content in sphinx. I suppose a |
I don't think a standalone Ultimately, it feels like we're trying to pick from several less than ideal (maybe even bad) options because the functionality we really need isn't available/supported. We could think about trying to submit upstream patches to Sphinx to make them available... but I don't know how likely to succeed that is or what kind of timeframe it means. Barring upstream modifications, I feel like the directive is the least bad.
I also think I should point out that this problem is going to get bigger with the
And these sorts of complexities may come up in other protocols yet to be implemented as well. Looking ahead, a custom directive seems like it will be a cleaner solution for this more complex case:
(Obviously, that's very rough and needs some naming work, but just to give you an idea.) The usage enforcement features become even more important with this level of complexity, and if a directive is a better solution for this, then a directive for Sorry for dragging this out. If I had done a better job understanding Sphinx and docutils from the get go, we might not need to go through all this discussion. And while I know this doesn't seem like a big deal by itself, I'm also trying to look forward to ensuring this extension maintains a fairly consistent experience to make using it easier. |
5ee986c
to
6451d43
Compare
This set of changes implements a mechanism for specifying a replacement for "self" in the generated signatures (see #11). I had to make some fairly major changes to make this work, so please review them carefully. If there's better ways of solving any of these problems, I'll be happy to rework my changes.
The concerns I have:
meta
info field for specifying the new name. I chose this because I couldn't find any other simple way of providing an input value to thepy:method
domain directive; it seems to be effectively closed to extension. Is there a better approach to providing the name?meta
info field, the existing transform was occurring much too late in the process of generating documentation. By the time it was invoked,meta
info fields had been filtered out of the docstring. To solve this, I had to convert the transform into an event handler and specify its priority to invoke it before the meta filtering event. Is there a better way to make the transform happen early enough in the process?py:method
with aselfref
field, and a test on autodoc with aselfref
field. One thing I don't like about this is that there are now four separate files listing all the methods this project covers. To try to ensure that they remain in sync as the project covers more special methods, I gave the tests a shared expected output (with some filtering to simplify the autodoc cases). Is there a better way to maintain or enforce consistency between all the files? We could generate them automatically somehow, but it would make the project more complex.