poetry: Dulwich does not support Dumb Git transport

  • I am on the latest stable Poetry version, installed using a recommended method.
  • I have searched the issues of this repo and believe that this is not a duplicate.
  • I have consulted the FAQ and blog for any relevant entries or release notes.
  • If an exception occurs when executing a command, I executed it again in debug mode (-vvv option) and have included the output below.

Issue

I’m unable to add git dependencies both via https and ssh. If I just do a regular git clone <repo> it works for ssh.

HTTPS

❯ poetry add git+https://github.com:mbuesch/pyprofibus.git -vvv
Using virtualenv: C:\Users\rruiter\Miniconda3\envs\profinet310
[keyring.backend] Loading KWallet
[keyring.backend] Loading SecretService
[keyring.backend] Loading Windows
[keyring.backend] Loading chainer
[keyring.backend] Loading libsecret
[keyring.backend] Loading macOS
[urllib3.connectionpool] Starting new HTTPS connection (1): github.com:443
[urllib3.connectionpool] https://github.com:443 "GET /mbuesch/pyprofibus.git/info/refs?service=git-upload-pack HTTP/1.1" 200 None
Cloning https://github.com/mbuesch/pyprofibus.git at 'HEAD' to C:\Users\rruiter\Miniconda3\envs\profinet310\src\pyprofibus
[urllib3.connectionpool] Starting new HTTPS connection (1): git.bues.ch:443
[urllib3.connectionpool] https://git.bues.ch:443 "GET /git/crcgen.git/info/refs?service=git-upload-pack HTTP/1.1" 200 817

  Stack trace:

  23  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:329 in run
       327│
       328│             try:
     → 329│                 exit_code = self._run(io)
       330│             except Exception as e:
       331│                 if not self._catch_exceptions:

  22  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\application.py:185 in _run
       183│         self._load_plugins(io)
       184│
     → 185│         exit_code: int = super()._run(io)
       186│         return exit_code
       187│

  21  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:423 in _run
       421│             io.input.set_stream(stream)
       422│
     → 423│         exit_code = self._run_command(command, io)
       424│         self._running_command = None
       425│

  20  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:465 in _run_command
       463│
       464│         if error is not None:
     → 465│             raise error
       466│
       467│         return event.exit_code

  19  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:449 in _run_command
       447│
       448│             if event.command_should_run():
     → 449│                 exit_code = command.run(io)
       450│             else:
       451│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

  18  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\base_command.py:119 in run
       117│         io.input.validate()
       118│
     → 119│         status_code = self.execute(io)
       120│
       121│         if status_code is None:

  17  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\command.py:83 in execute
        81│
        82│         try:
     →  83│             return self.handle()
        84│         except KeyboardInterrupt:
        85│             return 1

  16  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\add.py:158 in handle
       156│             return 0
       157│
     → 158│         requirements = self._determine_requirements(
       159│             packages,
       160│             allow_prereleases=self.option("allow-prereleases"),

  15  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:357 in _determine_requirements
       355│
       356│         result = []
     → 357│         for requirement in self._parse_requirements(requires):
       358│             if "git" in requirement or "url" in requirement or "path" in requirement:
       359│                 result.append(requirement)

  14  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:416 in _parse_requirements
       414│             cwd = Path.cwd()
       415│
     → 416│         return [
       417│             parse_dependency_specification(
       418│                 requirement=requirement,

  13  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:417 in <listcomp>
       415│
       416│         return [
     → 417│             parse_dependency_specification(
       418│                 requirement=requirement,
       419│                 env=self.env if isinstance(self, EnvCommand) else None,

  12  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:216 in parse_dependency_specification
       214│
       215│     specification = (
     → 216│         _parse_dependency_specification_url(requirement, env=env)
       217│         or _parse_dependency_specification_path(requirement, cwd=cwd)
       218│         or _parse_dependency_specification_simple(requirement)

  11  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:68 in _parse_dependency_specification_url
        66│
        67│     if url_parsed.scheme in ["git+https", "git+ssh"]:
     →  68│         return _parse_dependency_specification_git_url(requirement, env)
        69│
        70│     if url_parsed.scheme in ["http", "https"]:

  10  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:49 in _parse_dependency_specification_git_url
        47│
        48│     source_root = env.path.joinpath("src") if env else None
     →  49│     package = Provider.get_package_from_vcs(
        50│         "git",
        51│         url=url.url,

   9  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\puzzle\provider.py:341 in get_package_from_vcs
       339│             raise ValueError(f"Unsupported VCS dependency {vcs}")
       340│
     → 341│         return _get_package_from_git(
       342│             url=url,
       343│             branch=branch,

   8  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\puzzle\provider.py:95 in _get_package_from_git
        93│     source_root: Path | None = None,
        94│ ) -> Package:
     →  95│     source = Git.clone(
        96│         url=url,
        97│         source_root=source_root,

   7  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:427 in clone
       425│             if not cls.is_using_legacy_client():
       426│                 local = cls._clone(url=url, refspec=refspec, target=target)
     → 427│                 cls._clone_submodules(repo=local)
       428│                 return local
       429│         except HTTPUnauthorized:

   6  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:356 in _clone_submodules
       354│                         continue
       355│
     → 356│                 cls.clone(
       357│                     url=url.decode("utf-8"),
       358│                     source_root=source_root,

   5  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:426 in clone
       424│         try:
       425│             if not cls.is_using_legacy_client():
     → 426│                 local = cls._clone(url=url, refspec=refspec, target=target)
       427│                 cls._clone_submodules(repo=local)
       428│                 return local

   4  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:258 in _clone
       256│             local = Repo(str(target))
       257│
     → 258│         remote_refs = cls._fetch_remote_refs(url=url, local=local)
       259│
       260│         logger.debug(

   3  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:201 in _fetch_remote_refs
       199│
       200│         with local:
     → 201│             result: FetchPackResult = client.fetch(
       202│                 path,
       203│                 local,

   2  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:837 in fetch
        835│             f, commit, abort = target.object_store.add_pack()
        836│         try:
     →  837│             result = self.fetch_pack(
        838│                 path,
        839│                 determine_wants,

   1  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:2076 in fetch_pack
       2074│         """
       2075│         url = self._get_url(path)
     → 2076│         refs, server_capabilities, url = self._discover_references(
       2077│             b"git-upload-pack", url
       2078│         )

  AttributeError

  'NoneType' object has no attribute 'startswith'

  at ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:1946 in _discover_references
      1942│                 )
      1943│             base_url = resp.redirect_location[: -len(tail)]
      1944│
      1945│         try:
    → 1946│             self.dumb = not resp.content_type.startswith("application/x-git-")
      1947│             if not self.dumb:
      1948│                 proto = Protocol(read, None)
      1949│                 # The first line should mention the service
      1950│                 try:

SSH

❯ poetry add git+ssh://github.com:mbuesch/pyprofibus.git -vvv
Using virtualenv: C:\Users\rruiter\Miniconda3\envs\profinet310

  Stack trace:

  3  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:1149 in fetch_pack
      1147│         with proto:
      1148│             try:
    → 1149│                 refs, server_capabilities = read_pkt_refs(proto.read_pkt_seq())
      1150│             except HangupException as exc:
      1151│                 raise _remote_error_from_stderr(stderr) from exc

  2  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:253 in read_pkt_refs
       251│     refs = {}
       252│     # Receive refs from server
    →  253│     for pkt in pkt_seq:
       254│         (sha, ref) = pkt.rstrip(b"\n").split(None, 1)
       255│         if sha == b"ERR":

  1  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\protocol.py:277 in read_pkt_seq
      275│             flush-pkt.
      276│         """
    → 277│         pkt = self.read_pkt_line()
      278│         while pkt:
      279│             yield pkt

  HangupException

  The remote server unexpectedly closed the connection.

  at ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\protocol.py:220 in read_pkt_line
      216│
      217│         try:
      218│             sizestr = read(4)
      219│             if not sizestr:
    → 220│                 raise HangupException()
      221│             size = int(sizestr, 16)
      222│             if size == 0:
      223│                 if self.report_activity:
      224│                     self.report_activity(4, "read")

The following error occurred when trying to handle this error:


  Stack trace:

  20  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:329 in run
       327│
       328│             try:
     → 329│                 exit_code = self._run(io)
       330│             except Exception as e:
       331│                 if not self._catch_exceptions:

  19  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\application.py:185 in _run
       183│         self._load_plugins(io)
       184│
     → 185│         exit_code: int = super()._run(io)
       186│         return exit_code
       187│

  18  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:423 in _run
       421│             io.input.set_stream(stream)
       422│
     → 423│         exit_code = self._run_command(command, io)
       424│         self._running_command = None
       425│

  17  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:465 in _run_command
       463│
       464│         if error is not None:
     → 465│             raise error
       466│
       467│         return event.exit_code

  16  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\application.py:449 in _run_command
       447│
       448│             if event.command_should_run():
     → 449│                 exit_code = command.run(io)
       450│             else:
       451│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

  15  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\base_command.py:119 in run
       117│         io.input.validate()
       118│
     → 119│         status_code = self.execute(io)
       120│
       121│         if status_code is None:

  14  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\cleo\commands\command.py:83 in execute
        81│
        82│         try:
     →  83│             return self.handle()
        84│         except KeyboardInterrupt:
        85│             return 1

  13  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\add.py:158 in handle
       156│             return 0
       157│
     → 158│         requirements = self._determine_requirements(
       159│             packages,
       160│             allow_prereleases=self.option("allow-prereleases"),

  12  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:357 in _determine_requirements
       355│
       356│         result = []
     → 357│         for requirement in self._parse_requirements(requires):
       358│             if "git" in requirement or "url" in requirement or "path" in requirement:
       359│                 result.append(requirement)

  11  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:416 in _parse_requirements
       414│             cwd = Path.cwd()
       415│
     → 416│         return [
       417│             parse_dependency_specification(
       418│                 requirement=requirement,

  10  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\console\commands\init.py:417 in <listcomp>
       415│
       416│         return [
     → 417│             parse_dependency_specification(
       418│                 requirement=requirement,
       419│                 env=self.env if isinstance(self, EnvCommand) else None,

   9  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:216 in parse_dependency_specification
       214│
       215│     specification = (
     → 216│         _parse_dependency_specification_url(requirement, env=env)
       217│         or _parse_dependency_specification_path(requirement, cwd=cwd)
       218│         or _parse_dependency_specification_simple(requirement)

   8  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:68 in _parse_dependency_specification_url
        66│
        67│     if url_parsed.scheme in ["git+https", "git+ssh"]:
     →  68│         return _parse_dependency_specification_git_url(requirement, env)
        69│
        70│     if url_parsed.scheme in ["http", "https"]:

   7  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\utils\dependency_specification.py:49 in _parse_dependency_specification_git_url
        47│
        48│     source_root = env.path.joinpath("src") if env else None
     →  49│     package = Provider.get_package_from_vcs(
        50│         "git",
        51│         url=url.url,

   6  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\puzzle\provider.py:341 in get_package_from_vcs
       339│             raise ValueError(f"Unsupported VCS dependency {vcs}")
       340│
     → 341│         return _get_package_from_git(
       342│             url=url,
       343│             branch=branch,

   5  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\puzzle\provider.py:95 in _get_package_from_git
        93│     source_root: Path | None = None,
        94│ ) -> Package:
     →  95│     source = Git.clone(
        96│         url=url,
        97│         source_root=source_root,

   4  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:426 in clone
       424│         try:
       425│             if not cls.is_using_legacy_client():
     → 426│                 local = cls._clone(url=url, refspec=refspec, target=target)
       427│                 cls._clone_submodules(repo=local)
       428│                 return local

   3  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:258 in _clone
       256│             local = Repo(str(target))
       257│
     → 258│         remote_refs = cls._fetch_remote_refs(url=url, local=local)
       259│
       260│         logger.debug(

   2  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\poetry\vcs\git\backend.py:201 in _fetch_remote_refs
       199│
       200│         with local:
     → 201│             result: FetchPackResult = client.fetch(
       202│                 path,
       203│                 local,

   1  ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:837 in fetch
        835│             f, commit, abort = target.object_store.add_pack()
        836│         try:
     →  837│             result = self.fetch_pack(
        838│                 path,
        839│                 determine_wants,

  HangupException

  d\\rruiter@github.com: Permission denied (publickey).

  at ~\AppData\Roaming\pypoetry\venv\lib\site-packages\dulwich\client.py:1151 in fetch_pack
      1147│         with proto:
      1148│             try:
      1149│                 refs, server_capabilities = read_pkt_refs(proto.read_pkt_seq())
      1150│             except HangupException as exc:
    → 1151│                 raise _remote_error_from_stderr(stderr) from exc
      1152│             (
      1153│                 negotiated_capabilities,
      1154│                 symrefs,
      1155│                 agent,

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 21 (15 by maintainers)

Most upvoted comments

Glancing over the comments here, it looks like the cause was a mix of two things: an invalidly formatted URL and lack of dumb remote repository support in dulwich (masked by incorrect handling of a missing Content-Type header).

The None Content-Type is an error handling bug; I agree Dulwich should raise a different exception, but it’s not the root cause of the issues @rruiter87 is hitting

https://git.bues.ch/git/crcgen.git/ is what stood out to me specifically, however, I did not realize it was a public repo; my bad. It looks like this is a submodule using the ‘dumb’ HTTP transport – I’m honestly not sure if Dulwich supports dumb HTTP as it’s generally considered deprecated, but it helps that everything is publicly visible.

SSH no, HTTPS yes

I set the option with

 ❯ poetry config experimental.system-git-client true

SSH 🔴

❯ poetry add git+ssh://github.com:mbuesch/pyprofibus.git -vvv
Loading configuration file C:\Users\rruiter\AppData\Roaming\pypoetry\config.toml
Using virtualenv: C:\Users\rruiter\Miniconda3\envs\profinet310
Cloning 'github.com:mbuesch/pyprofibus.git' using system git client

Failed to clone github.com:mbuesch/pyprofibus.git, check your git configuration and permissions for this repository.

HTTPS 🟢

❯ poetry add git+https://github.com:mbuesch/pyprofibus.git -vvv
Loading configuration file C:\Users\rruiter\AppData\Roaming\pypoetry\config.toml
Using virtualenv: C:\Users\rruiter\Miniconda3\envs\profinet310
Cloning 'https://github.com/mbuesch/pyprofibus.git' using system git client

Updating dependencies
Resolving dependencies...
   1: fact: profinettest is 0.1.0
   1: derived: profinettest
   1: fact: profinettest depends on pyprofibus (1.11)
   1: selecting profinettest (0.1.0)
   1: derived: pyprofibus (1.11) @ git+https://github.com/mbuesch/pyprofibus.git
   1: selecting pyprofibus (1.11 78f06da)
   1: Version solving took 0.004 seconds.
   1: Tried 1 solutions.

Writing lock file

Finding the necessary packages for the current system

Package operations: 1 install, 0 updates, 0 removals

  • Installing pyprofibus (1.11 78f06da)