Must have a url pipit

Hello,

I’m in the final step of publishing python package to PyPi, I got the following error. and it’s extremely confusing. What does the url here refer to? and how can I get it working. thank you for your help!

25hWARNING Error during upload. Retry with the --verbose option for more details.
ERROR HTTPError: 400 Bad Request from upload.pypi.org · PyPI
Must have a URL. See
Core metadata specifications - Python Packaging User Guide for more
information.

You say you got this error message:

 WARNING  Error during upload. Retry with the --verbose option for 
 more details.
 ERROR    HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/
          Must have a URL. See
          https://packaging.python.org/specifications/core-metadata 
          for more information.

Did you run with the --verbose option?

Having a browse of the suggestion in the message, maybe this:
https://packaging.python.org/en/latest/specifications/core-metadata/#project-url-multiple-use

Maybe you could post your pyproject.toml file? Does it have a
[project.urls] section?

Sue, I don’t have project.urls. But I have 'dynamic = [“version”, “description”, “authors”, “urls”, “keywords”]

[build-system]
requires = ["hatchling>=1.5.0", "jupyterlab>=4.0.0,<5", "hatch-nodejs-version>=0.3.2"]
build-backend = "hatchling.build"

[project]
name = "msgbridge"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.8"
classifiers = [
    "Framework :: Jupyter",
    "Framework :: Jupyter :: JupyterLab",
    "Framework :: Jupyter :: JupyterLab :: 4",
    "Framework :: Jupyter :: JupyterLab :: Extensions",
    "Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt",
    "License :: OSI Approved :: BSD License",
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]
dependencies = [
]
dynamic = ["version", "description", "authors", "urls", "keywords"]

[tool.hatch.version]
source = "nodejs"

[tool.hatch.metadata.hooks.nodejs]
fields = ["description", "authors", "urls"]

[tool.hatch.build.targets.sdist]
artifacts = ["msgbridge/labextension"]
exclude = [".github", "binder"]

[tool.hatch.build.targets.wheel.shared-data]
"msgbridge/labextension" = "share/jupyter/labextensions/msgbridge"
"install.json" = "share/jupyter/labextensions/msgbridge/install.json"

[tool.hatch.build.hooks.version]
path = "msgbridge/_version.py"

[tool.hatch.build.hooks.jupyter-builder]
dependencies = ["hatch-jupyter-builder>=0.5"]
build-function = "hatch_jupyter_builder.npm_builder"
ensured-targets = [
    "msgbridge/labextension/static/style.js",
    "msgbridge/labextension/package.json",
]
skip-if-exists = ["msgbridge/labextension/static/style.js"]

[tool.hatch.build.hooks.jupyter-builder.build-kwargs]
build_cmd = "build:prod"
npm = ["jlpm"]

[tool.hatch.build.hooks.jupyter-builder.editable-build-kwargs]
build_cmd = "install:extension"
npm = ["jlpm"]
source_dir = "src"
build_dir = "msgbridge/labextension"

[tool.jupyter-releaser.options]
version_cmd = "hatch version"

[tool.jupyter-releaser.hooks]
before-build-npm = [
    "python -m pip install 'jupyterlab>=4.0.0,<5'",
    "jlpm",
    "jlpm build:prod"
]
before-build-python = ["jlpm clean:all"]

[tool.check-wheel-contents]
ignore = ["W002"]

and here’s the output when I run local

twine upload dist/* --verbose
INFO     Using configuration from /Users/delongzhai/.pypirc                                                                                                  
Uploading distributions to https://upload.pypi.org/legacy/
INFO     dist/msgbridge-0.1.0-py3-none-any.whl (14.9 KB)                                                                                                     
INFO     dist/msgbridge-0.1.0.tar.gz (134.7 KB)                                                                                                              
INFO     password set from config file                                                                                                                       
INFO     username: __token__                                                                                                                                 
INFO     password: <hidden>                                                                                                                                  
Uploading msgbridge-0.1.0-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 24.6/24.6 kB • 00:00 • 92.9 MB/s
INFO     Response from https://upload.pypi.org/legacy/:                                                                                                      
         400 Must have a URL. See https://packaging.python.org/specifications/core-metadata for more information.                                            
INFO     <html>                                                                                                                                              
          <head>                                                                                                                                             
           <title>400 Must have a URL. See https://packaging.python.org/specifications/core-metadata for more information.</title>                           
          </head>                                                                                                                                            
          <body>                                                                                                                                             
           <h1>400 Must have a URL. See https://packaging.python.org/specifications/core-metadata for more information.</h1>                                 
           The server could not comply with the request since it is either malformed or otherwise incorrect.<br/><br/>                                       
         Must have a URL. See https://packaging.python.org/specifications/core-metadata for more information.                                                
                                                                                                                                                             
                                                                                                                                                             
          </body>                                                                                                                                            
         </html>                                                                                                                                             
ERROR    HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/                                     

Based on the warehouse source code, what is meant is that project.urls for some reason has an empty url instead of just not existing. I imagine this is a bug in hatch, but you should be able to work around this by just not including "urls" in dynamic.

1 Like

Hmm, no more informative.

What if you provided a project.urls ? If this is you: GitHub - ZDL-LLC/msgbridge
you coude provide that perhaps?

Untested example:

 [project.urls]
 URL = https://github.com/ZDL-LLC/msgbridge

I see you’ve got a url in your setup.py. Just replicate to the
pyproject.toml. In fact, do you even need a setup.py?

BTW, msgbridge is a very generic top level name for what seems to be
tiny piece of special purpose TypeScript. Had you considered something
like zdl-msgbridge etc?

sure thank you. I removed all “urls” occurrence in pyproject.toml, which thankfully work out.

thank you for your response. Yes the link you share was me. Was trying to go through the tutorial on Jupyter extension development. But there’s something that just doesn’t come together.

I think the naming of it come from “bridging JupyterLite REPL iframe and postMessage the json object to hosting application”. That name does sound to be very generic and functionality-limited. I agree that it should be updated. However, is there anything I should watch out. Like deleting all from PiPy?

I just deleted all PiPy. and gave it another good name. GitHub - ZDL-LLC/jupyter-repl-msgbridge

1 Like