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

Empty body of METADATA results into an error when twine check #908

Open
hzhangxyz opened this issue Jun 11, 2022 · 5 comments
Open

Empty body of METADATA results into an error when twine check #908

hzhangxyz opened this issue Jun 11, 2022 · 5 comments

Comments

@hzhangxyz
Copy link

Your Environment

twine version is 4.0.1 (install from pip)
python version is 3.10.5 (install by system package manager)
linux (arch linux)

The Issue

I create a wheel file with cibuildwheel(https://github.com/pypa/cibuildwheel), in which METADATA has an empty body like

Metadata-Version: 2.1
Name: PyTAT
Version: 0.2.14
Summary: python binding for TAT(TAT is A Tensor library)
Home-page: https://github.com/hzhangxyz/TAT
Author: Hao Zhang
Author-email: [email protected]
License: GPLv3
License-File: LICENSE.md
Requires-Dist: numpy

old version cibuildwheel does not leave body empty, and add a word "UNKNOWN" like:

Metadata-Version: 2.1
Name: PyTAT
Version: 0.2.13
Summary: python binding for TAT(TAT is A Tensor library)
Home-page: https://github.com/hzhangxyz/TAT
Author: Hao Zhang
Author-email: [email protected]
License: GPLv3
Platform: UNKNOWN
License-File: LICENSE.md
Requires-Dist: numpy

UNKNOWN

With wheel file created with new version cibuildwheel, twien check failed with message:

ERROR    `long_description` has syntax errors in markup and would not be rendered on PyPI.
         No content rendered from RST source.

Steps to Reproduce

Just delete the description body of package can reproduce.


I also post an issue at pypa/cibuildwheel#1131 but it seems it is not their fault.

because https://peps.python.org/pep-0566/#description saying

In addition to the Description header field, the distribution’s description may instead be provided in the message body (i.e., after a completely blank line following the headers, with no indentation or other special formatting necessary).

It may be provided, so not to do so should be permitted.

@hzhangxyz hzhangxyz changed the title Empty body will raise an error. Empty body will raise an error when "twine check" Jun 11, 2022
@hzhangxyz hzhangxyz changed the title Empty body will raise an error when "twine check" Empty body of METADATA will raise an error when "twine check" Jun 11, 2022
@hzhangxyz hzhangxyz changed the title Empty body of METADATA will raise an error when "twine check" Empty body of METADATA results into an error when "twine check" Jun 11, 2022
@hzhangxyz hzhangxyz changed the title Empty body of METADATA results into an error when "twine check" Empty body of METADATA results into an error when twine check Jun 12, 2022
@bhrutledge
Copy link
Contributor

bhrutledge commented Jun 23, 2022

I did some experimenting with an example package. It looks like the UNKNOWN behavior changed in setuptools v62.2.0, with the merge of pypa/setuptools#3299.

I was able to reproduce the error using a wheel:

% rm -Rf build && python3 -m build -w
...
Successfully built example_pkg_bhrutledge-0.0.5-py3-none-any.whl

% unzip -c dist/example_pkg_bhrutledge-0.0.5-py3-none-any.whl example_pkg_bhrutledge-0.0.5.dist-info/METADATA
Metadata-Version: 2.1
Name: example-pkg-bhrutledge
Version: 0.0.5
Summary: A small example package
Home-page: https://github.com/pypa/sampleproject
Author: Example Author
Author-email: [email protected]
Project-URL: Bug Tracker, https://github.com/pypa/sampleproject/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/rst
License-File: LICENSE



% twine check dist/example_pkg_bhrutledge-0.0.5-py3-none-any.whl
Checking dist/example_pkg_bhrutledge-0.0.5-py3-none-any.whl: FAILED
ERROR    `long_description` has syntax errors in markup and would not be rendered on PyPI.
         no output rendered

However, I'm not seeing the same behavior from the sdist:

% rm -Rf dist && python3 -m build -s
...
Successfully built example-pkg-bhrutledge-0.0.5.tar.gz

% tar Oxvf dist/example-pkg-bhrutledge-0.0.5.tar.gz 'example-pkg-bhrutledge-0.0.5/PKG-INFO'
Metadata-Version: 2.1
Name: example-pkg-bhrutledge
Version: 0.0.5
Summary: A small example package
Home-page: https://github.com/pypa/sampleproject
Author: Example Author
Author-email: [email protected]
Project-URL: Bug Tracker, https://github.com/pypa/sampleproject/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
License-File: LICENSE

% twine check dist/example-pkg-bhrutledge-0.0.5.tar.gz
Checking dist/example-pkg-bhrutledge-0.0.5.tar.gz: PASSED with warnings
WARNING  `long_description_content_type` missing. defaulting to `text/x-rst`.
WARNING  `long_description` missing.

Here's the relevant configuration:

https://github.com/bhrutledge/example-pkg-bhrutledge/blob/missing-description/pyproject.toml
https://github.com/bhrutledge/example-pkg-bhrutledge/blob/missing-description/setup.cfg

The warnings are what I would expect, given the missing long_description in setup.cfg. It looks like METADATA file has an extra blank line at the end:

--- example-pkg-bhrutledge-0.0.5/PKG-INFO       2022-06-23 08:18:59.000000000 -0400
+++ example_pkg_bhrutledge-0.0.5.dist-info/METADATA     2022-06-23 12:22:08.000000000 -0400
@@ -12,3 +12,4 @@
 Requires-Python: >=3.6
 Description-Content-Type: text/rst
 License-File: LICENSE
+

I wonder if that's what's tripping up Twine (or readme_renderer under the hood), though I'm also seeing the same error with backends other than setuptools (e.g. hatchling and flit) that don't seem to add an extra line.

Need to investigate further.

@miketheman
Copy link
Member

miketheman commented Aug 7, 2022

@bhrutledge One difference I found from reading the scenario:

Description-Content-Type appears in the built wheel METADATA and not in the sdist

I tried to repro your findings, but couldn't find a build module - where does that come from? never mind, it's using https://pypi.org/project/build/ - whoops.

slonopotamus added a commit to slonopotamus/ue4-docker that referenced this issue Mar 10, 2023
Multiple things failed at once:
1. Link to readme was lost during conversion to `pyproject.toml` in f668317. This commit restores it.
2. PyPI only accepts rst/markdown/txt, so convert README back to markdown
3. twine has a bug that prevents upload from working without readme: pypa/twine#908

Also run `twine check` on CI to detect `pyproject.toml` metadata errors earlier
slonopotamus added a commit to slonopotamus/ue4-docker that referenced this issue Mar 10, 2023
Multiple things failed at once:
1. Link to readme was lost during conversion to `pyproject.toml` in f668317. This commit restores it.
2. PyPI only accepts rst/markdown/txt, so convert README back to markdown
3. twine has a bug that prevents upload from working without readme: pypa/twine#908

Also run `twine check` on CI to detect `pyproject.toml` metadata errors earlier
slonopotamus added a commit to slonopotamus/ue4-docker that referenced this issue Mar 10, 2023
Multiple things failed at once:
1. Link to readme was lost during conversion to `pyproject.toml` in f668317. This commit restores it.
2. PyPI only accepts rst/markdown/txt, so undo conversion of readme to AsciiDoc that was done in 55191a7
3. twine has a bug that prevents upload from working without readme: pypa/twine#908

Also run `twine check` on CI to detect `pyproject.toml` metadata errors earlier
slonopotamus added a commit to slonopotamus/ue4-docker that referenced this issue Mar 10, 2023
Multiple things failed at once:
1. Link to readme was lost during conversion to `pyproject.toml` in f668317. This commit restores it.
2. PyPI only accepts rst/markdown/txt, so undo conversion of readme to AsciiDoc that was done in 55191a7
3. twine has a bug that prevents upload from working without readme: pypa/twine#908

Also run `twine check` on CI to detect `pyproject.toml` metadata errors earlier
slonopotamus added a commit to adamrehn/ue4-docker that referenced this issue Mar 10, 2023
Multiple things failed at once:
1. Link to readme was lost during conversion to `pyproject.toml` in f668317. This commit restores it.
2. PyPI only accepts rst/markdown/txt, so undo conversion of readme to AsciiDoc that was done in 55191a7
3. twine has a bug that prevents upload from working without readme: pypa/twine#908

Also run `twine check` on CI to detect `pyproject.toml` metadata errors earlier
anthrotype added a commit to anthrotype/brotli that referenced this issue Sep 6, 2023
twine (the tool we use to upload packages to PyPI) is currently failing if the long_description (used to render a project's page on PyPI website) is not set. Somehow it complains that it is not well formatted reStructuredText, but it's simply empty...
This looks like a bug, or bad interaction between twince and setuptools, because the field is technically optional.
Also see pypa/twine#960 and pypa/twine#908.

This issue is currently preventing the upload of newly built Brotli v1.1.0 Python wheels to PyPI:
google/brotli-wheels#18 (comment)

Anyway, we may well set the long_description to the content of the README.md file, as it's customary for python projects.
eustas pushed a commit to google/brotli that referenced this issue Sep 7, 2023
twine (the tool we use to upload packages to PyPI) is currently failing if the long_description (used to render a project's page on PyPI website) is not set. Somehow it complains that it is not well formatted reStructuredText, but it's simply empty...
This looks like a bug, or bad interaction between twince and setuptools, because the field is technically optional.
Also see pypa/twine#960 and pypa/twine#908.

This issue is currently preventing the upload of newly built Brotli v1.1.0 Python wheels to PyPI:
google/brotli-wheels#18 (comment)

Anyway, we may well set the long_description to the content of the README.md file, as it's customary for python projects.
@jaraco
Copy link
Member

jaraco commented May 2, 2024

+1; I encountered this issue also today when attempting to check a package with minimal metadata. According to the spec, only Metadata-Version, Name, and Version are required. Maybe check should warn when the long description is empty, but it shouldn't error.

@sigmavirus24
Copy link
Member

+1; I encountered this issue also today when attempting to check a package with minimal metadata. According to the spec, only Metadata-Version, Name, and Version are required. Maybe check should warn when the long description is empty, but it shouldn't error.

The explicit purpose of check is to verify the long description renders without errors on PyPI. It does almost nothing else.

@DarkaMaul
Copy link
Contributor

Sorry to bump this issue. I had the same issue today in one of my runs.

Breadcrumb

  • twine check performs a verification on the package metadata ( here )

  • Notably, these verification includes that the description content is properly formatted, If no description is provided, only a warning is emitted.

  • The description field is parsed from the Wheel class which uses internally pkginfo which relies on Python email parser to parse the package metadata. The description is considered to be the payload of the message.

  • The Python email parser first parses the headers lines, then considers anything after the headers lines to be the message body (if the message type is not specified).

Bug

If the description is empty, the payload will be set to self._cur.set_payload(EMPTYSTRING.join([])).
This results in an empty string if the description is empty.

If we go back at twine:

if description is None or description.rstrip() == "UNKNOWN":
warnings.append("`long_description` missing.")
elif renderer:
rendering_result = renderer.render(
description, stream=render_warning_stream, **params
)
if rendering_result is None:
is_ok = False

description is not None so we try to render using one of the renderer (by default text/x-rst).
renderer which will returns None for an empty string, generating an error

from twine.commands.check import _RENDERERS
renderer = _RENDERERS.get("text/x-rst")
assert renderer.render("") is None

@DarkaMaul DarkaMaul mentioned this issue Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants