pypiにpackageをuploadするときに、HTTPError: 400 Client Error: The description failed to render in the default format of reStructuredText.が出た話。

pypiにuploadした時に以下のようなエラーが出た。

$ python setup.py sdist bdist_wheel
$ twine upload dist/<package>
...
HTTPError: 400 Client Error: The description failed to render in the default format of reStructuredText. See https://pypi.org/help/#description-content-type for more information. for url: https://upload.pypi.org/legacy/

一応verboseオプション付きでメッセージを表示してみる。

$ twine upload --verbose dist/<package>
...
Content received from server:
<html>
 <head>
  <title>400 The description failed to render in the default format of reStructuredText. See https://pypi.org/help/#description-content-type for more information.</title>
 </head>
 <body>
  <h1>400 The description failed to render in the default format of reStructuredText. See https://pypi.org/help/#description-content-type for more information.</h1>
  The server could not comply with the request since it is either malformed or otherwise incorrect.<br/><br/>
The description failed to render in the default format of reStructuredText. See https://pypi.org/help/#description-content-type for more information.


 </body>
</html>
HTTPError: 400 Client Error: The description failed to render in the default format of reStructuredText. See https://pypi.org/help/#description-content-type for more information. for url: https://upload.pypi.org/legacy/

このときのパッケージのsetup.pyに description-content-type を指定していなかった(結構前からtext/markdownを指定するとreadmeをmarkdownで書ける様になっている。デフォルトはReST)。

ただし今回に限って言うと、エラーメッセージがほとんどかけらも役に立たない。唯一役に立つのはrenderに失敗しているということがわかるだけ。なので、ヘルプメッセージの指すリンク先をみてdescription-content-typeを指定しても意味がない。

(追記: 以下の文が役に立つ。一応。)

PyPI will reject uploads if the description fails to render. To check a description locally for validity, you may use readme_renderer, which is the same description renderer used by PyPI.

(追記おしまい)

ちなみに、text/x-rstに変えた場合のメッセージは以下の様に変わる。

HTTPError: 400 Client Error: The description failed to render for 'text/x-rst'. See https://pypi.org/help/#description-content-type for more information. for url: https://upload.pypi.org/legacy/

readme_renderer

解決にはこのPRが参考になった。

何やら以下の様な感じらしい。

  • readmeのrenderingにはreadme_renderer パッケージを利用している
  • 少しのwarningであってもfailed扱いになる

github.com

実際試してみたら以下のようなwarningが出ていた。これだけのwarningでもだめ。

$ python -m readme_renderer README.rst
<string>:417: (WARNING/2) Title underline too short.

available info (extensions and additional modules)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

このときの環境

$ pip freeze | grep -i readme
readme-renderer==24.0

追記

twine checkを教えてもらった。たしかに存在する。便利そう。

$ twine -h
usage: twine [-h] [--version] {check,register,upload}

positional arguments:
  {check,register,upload}

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit

$ twine check dist/<package>
Checking distribution dist/<package>-py2.py3-none-any.whl: Passed

有効な値を頭の中に記憶して置かなければいけないインターフェイスはツライという話

github.com

はじめに

有効な値を頭の中に記憶して置かなければいけないインターフェイスはツライという話。 そんなわけで、kamidanaでもextensionsとadditional modulesについて組み込みのものの情報だけは表示してくれるようにしてみた。

extensions

extnesions はjinja2のextensionsそのもの。詳しくはここ。

以下の様にして使う。jinja2.ext は省略できる。

$ kamidana -e <extension name> <template>

たとえば、loop中でcontinue,breakが使える様になる拡張がある(利用例)

additional modules

こちらは、kamidanaのもの、templateが利用する関数やフィルタをその場で渡して利用できるようにする機能。

以下の様にして使う。kamidana.additionals は省略できる。

$ kamidana -a <additional module> <template>

例えば、単数形を複数形にするものがあったり、スネークケースやケバブケースやキャメルケースに変換するnamingというmoduleが組込で入っている(利用例)。

それぞれ渡せる値を調べるのが面倒

それぞれ渡せる値を調べるのが面倒だった。なので有効な値を一覧として見たいというissueはずっと作ってはいたのだけれど。包括的な方法が思いつかなかった(実装するのが面倒とも言う)ので放置していた。

考えてみると組み込みのものだけ分かればとりあえず十分なので、部分的なサポートをすることにした。

具体的には --list-info というオプションを付加して実行すると有効なものをそれぞれ表示する。フォーマットを考えるのが面倒だったのでJSONにした。

$ kamidana --list-info
extensions are used by `-e`, additional modules are used by `-a`.
{
  "extensions": {
    "jinja2.ext.i18n": "This extension adds gettext support to Jinja2.",
    "jinja2.ext.do": "Adds a `do` tag to Jinja2 that works like the print statement just",
    "jinja2.ext.loopcontrols": "Adds break and continue to the template engine.",
    "jinja2.ext.with_": "Extensions can be used to add extra functionality to the Jinja template",
    "jinja2.ext.autoescape": "Extensions can be used to add extra functionality to the Jinja template"
  },
  "additional_modules": {
    "kamidana.additionals.reader": "Reading from other resources (e.g. read_from_file, read_from_command)",
    "kamidana.additionals.naming": "Naming helpers (e.g. snakecase, kebabcase, ... pluralize, singularize)"
  }
}

ついでにちょっとした説明も加えることにした。extensionsの方はクラス自体のdocstringの1行目、additional modulesの方はそのモジュールのdocstring。

ただ一覧が出てきてもどう使えば良いかわからなくなりそうなので、stderrにちょっとした使いかたのヘルプメッセージを表示することにしてみた。

おしまい。