Skip to content
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

Add HTML markup to method/function return typehint #9225

Merged
merged 7 commits into from Jul 11, 2021

Conversation

doerwalter
Copy link
Contributor

Add a <span> around the type hint for the return value of a function or method.

When a Python function or method uses a type hint for the return value, e.g.

def f() -> Optional[str]
   ...

the autodoc extension (combined with a HTML writer) generates the following output for this:

<span class="sig-name descname">
	<span class="pre">f</span>
</span>
<span class="sig-paren">(</span><span class="sig-paren">)</span>
&#x2192;
<span class="pre">Optional</span>
<span class="p"><span class="pre">[</span></span>
<a class="reference external" href="..." title="...">
	<span class="pre">str</span>
</a>
<span class="p"><span class="pre">]</span></span>

This makes it impossible to add custom CSS markup for the return type hint only. This pull request changes the output to:

<span class="sig-name descname">
	<span class="pre">f</span>
</span>
<span class="sig-paren">(</span><span class="sig-paren">)</span>
<span class="sig-arrow">&#x2192;</span>
<span class="sig-returns">
	<span class="pre">Optional</span>
	<span class="p"><span class="pre">[</span></span>
	<a class="reference external" href="..." title="...">
		<span class="pre">str</span>
	</a>
	<span class="p"><span class="pre">]</span></span>
</span>

(i.e. it wraps the arrow in a <span class="sig-arrow"> and the return type itself in a <span class="sig-returns">.

This allows to add custom markup for the return type, i.e. something like this:

.sig-returns
{
	font-size: 90%;
	color: #999;
	letter-spacing: -1px;
}

Note that it's already possible to markup the type hints for parameters with the CSS selector .sig-param .n + .p + .n.

Copy link
Member

@tk0miya tk0miya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you rebase this into the 4.x branch?
In addition to this, please change sphinx/writers/html.py also. It's still alive.

@doerwalter
Copy link
Contributor Author

OK, I've rebased the branch. However I don't know where the two additional commits come from.

I also added an addtional <span> around the type hint, which makes it possible to show the type hint as a tooltip/popup with the following CSS:

.sig-return
{
	position: relative;
}

.sig-return-typehint
{
	position: absolute;
	top: 100%;
	left: 0;
	display: none;
	background-color: #fff;
	padding: 0.3em 0.6em;
	border: 1px solid #ccc;
	border-radius: 0.5em;
}

.sig-return:hover .sig-return-typehint
{
	display: inline;
}

And I applied the same change to sphinx/writers/html.py.

@doerwalter
Copy link
Contributor Author

I don't know how I can change to target branch of the pull request.

@doerwalter doerwalter changed the base branch from master to 4.x May 15, 2021 14:23
@doerwalter
Copy link
Contributor Author

OK, that was easy ;)

@tk0miya
Copy link
Member

tk0miya commented May 15, 2021

It seems you bring commits in the master branch into this PR. So you need to clean up the branch. Can you do that? If you don't know the way to do that, I'll do merging manually.

sphinx/writers/html.py Outdated Show resolved Hide resolved
Wrap the complete type hint in a additional <span> to enable showing the
typehint as a popup on hover.

Port changes to sphinx/writers/html.py.
@doerwalter
Copy link
Contributor Author

OK, I've rebased the branch to drop the two unrelated commits.

I've added a configuration option html_signaturereturn_icon that lets use replace the Unicode arrow &#x2192; with something else (e.g. a FontAwesome icons etc.) I haven't added the .. versionadded:: in doc/usage/configuration.rst because I don't know what the next version will be. 4.1? 5.0?

And the lines now should be short enough.

@doerwalter doerwalter requested a review from tk0miya May 20, 2021 08:50
@doerwalter
Copy link
Contributor Author

Some jobs seem to be failing with unable to access 'https://github.com/doerwalter/sphinx/': The requested URL returned error: 500. I don't know the reason for this, put IMHO that's unrelated to the change itself.

doc/usage/configuration.rst Outdated Show resolved Hide resolved
@@ -1191,6 +1191,11 @@ that use Sphinx's HTMLWriter class.

.. versionadded:: 3.5

.. confval:: html_signaturereturn_icon
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand why this is needed. Do you want to change the character of the allow?
Adding a new configuration increases the cost of maintenance. So I need to know this is really needed.

Note:

  • Which is better html_signaturereturn_icon and html_signature_return_icon.
  • If we'll determine to add this, testcase is needed.
  • If we'll determine to add this, it will be released as 4.x (maybe 4.1).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the typo.

Yes, I would like to be able to replace the arrow character.

My reason for this is that I would like to be able to display the function/method signature without the type hints. The type hints should however be displayed when the user hovers over an annotation icon with the mouse. This should work for both the parameter type hints and the return type hints. I would like to use consistent icons for this. For example https://fontawesome.com/icons/question-circle?style=regular for the parameter hint and https://fontawesome.com/icons/arrow-circle-right?style=regular for the return hint.

I find long signatures with type hints confusing. An extreme example from Sphinx (in application.py in Sphinx):

    def __init__(self, srcdir: str, confdir: Optional[str], outdir: str, doctreedir: str,
                 buildername: str, confoverrides: Dict = None,
                 status: IO = sys.stdout, warning: IO = sys.stderr,
                 freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None,
                 verbosity: int = 0, parallel: int = 0, keep_going: bool = False) -> None:

IMHO it's hard to see at first glance what is a parameter name, what is a type annotation and what is a default value (even with syntax highlighting). Without the type annotations this look much better:

    def __init__(self, srcdir, confdir, outdir, doctreedir, buildername, confoverrides,
                 status=sys.stdout, warning=sys.stderr, freshenv=False, warningiserror=False,
                 tags=None, verbosity=0, parallel=0, keep_going=False):

But I don't want to drop the type annotations completely, because they're useful when you are writing the function call. Fortunately on an HTML page we can have both: short and clear signatures and access to the type hints: By displaying the type hints on demand via a popup/tooltip.

I realize that this currently isn't possible for the parameter hint, but this patch makes it possible for the return hint.

I chose html_signaturereturn_icon for that name, because this matches the name for html_permalinks_icon.

However if we would introduce an icon for the parameter annotation in the future, html_signature_return_icon would make more sense, since we might have html_signature_param_icon too.

I'll start working on a testcase.

OK, I'll add a .. versionadded:: 4.1 to the documentation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your explanation. I understand it is worthy for you. But, I don't think it's also worthy for other users. Is it possible to change the icon by CSS hack or JS?

@doerwalter
Copy link
Contributor Author

OK, the test is done.

@doerwalter
Copy link
Contributor Author

Changing the icon via Javascript is annoying for the user (and Google doesn't like "layout shift" either). Changing it via CSS might be possible.

However I can of course always register my own translator like this:

class HTML5Translator(html5.HTML5Translator):
	def visit_desc_returns(self, node):
		self.body.append(' <span class="sig-return">')
		self.body.append('<span class="sig-return-icon">')
		self.body.append('<i class="fal fa-arrow-circle-right"></i>')
		self.body.append('</span> <span class="sig-return-typehint">')

	def depart_desc_returns(self, node):
		self.body.append('</span></span>')


def setup(app):
	app.set_translator("html", HTML5Translator, True)

But setting one configuration option is simpler that overwriting the translator.

If we don't want the additional configuration option, should I rollbak the pull request to the version without it?

@tk0miya
Copy link
Member

tk0miya commented Jun 13, 2021

Changing the icon via Javascript is annoying for the user (and Google doesn't like "layout shift" either). Changing it via CSS might be possible.

I wonder how many users need it. I still hesitate to add this as a configuration. I think it's enough to rewrite it via CSS or extension for now.

If we don't want the additional configuration option, should I rollbak the pull request to the version without it?

Yes. I perfectly agree to add <span> tag around a return typehint. So I'll merge soon if you separate this PR.

@doerwalter
Copy link
Contributor Author

OK, I've remove the configuration option html_signaturereturn_icon (but I've kept the test).

@doerwalter doerwalter requested a review from tk0miya June 14, 2021 12:05
@tk0miya tk0miya merged commit f40c283 into sphinx-doc:4.x Jul 11, 2021
@tk0miya
Copy link
Member

tk0miya commented Jul 11, 2021

Sorry for late. Just merged. Thank you for your contribution!

tk0miya added a commit that referenced this pull request Jul 11, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants