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

Poetry fails with GIT dependencies #10218

Open
IngLP opened this issue Feb 24, 2025 · 12 comments
Open

Poetry fails with GIT dependencies #10218

IngLP opened this issue Feb 24, 2025 · 12 comments
Labels
kind/bug Something isn't working as expected status/triage This issue needs to be triaged

Comments

@IngLP
Copy link

IngLP commented Feb 24, 2025

Description

Poetry fails to add a git dependency with the error:

AttributeError

'Tag' object has no attribute 'parents'

Workarounds

NO Workarounds! I am stuck!!

Poetry Installation Method

pip

Operating System

macOS 15.3.1

Poetry Version

2.1.1

Poetry Configuration

cache-dir = "/Users/lorenzop/Library/Caches/pypoetry"
data-dir = "/Users/lorenzop/Library/Application Support/pypoetry"
installer.max-workers = null
installer.no-binary = null
installer.only-binary = null
installer.parallel = false
installer.re-resolve = true
keyring.enabled = true
python.installation-dir = "{data-dir}/python"  # /Users/lorenzop/Library/Application Support/pypoetry/python
requests.max-retries = 0
solver.lazy-wheel = true
system-git-client = false
virtualenvs.create = true
virtualenvs.in-project = null
virtualenvs.options.always-copy = false
virtualenvs.options.no-pip = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/lorenzop/Library/Caches/pypoetry/virtualenvs
virtualenvs.prompt = "{project_name}-py{python_version}"
virtualenvs.use-poetry-python = false

Python Sysconfig

sysconfig.txt

sysconfig.log
Paste the output of 'python -m sysconfig', over this line.

Example pyproject.toml

[tool.poetry.dependencies]
python = "^3.12"
livekit-agents = { git = "https://github.com/livekit/agents.git",  tag = "[email protected]", subdirectory = "livekit-agents" }

Poetry Runtime Logs

poetry-runtime.log
lorenzop@MacBook-Pro-di-Lorenzo ~/D/R/Voicebot> poetry update --no-cache -vvvvvvv                                                                                                                                                                                                                                                                                 1 main!?
Loading configuration file /Users/lorenzop/Library/Application Support/pypoetry/config.toml
Loading configuration file /Users/lorenzop/Documents/Repo/Voicebot/poetry.toml
Disabling source caches
Using virtualenv: /Users/lorenzop/Library/Caches/pypoetry/virtualenvs/voicebot-7RZcLOD_-py3.12
Checking keyring availability: Checking if keyring is available
[keyring:keyring.backend] Loading KWallet
[keyring:keyring.backend] Loading SecretService
[keyring:keyring.backend] Loading Windows
[keyring:keyring.backend] Loading chainer
[keyring:keyring.backend] Loading libsecret
[keyring:keyring.backend] Loading macOS
Using keyring backend 'macOS Keyring'
Available
Updating dependencies
Resolving dependencies...
 1: fact: voicebot is 0.1.0
 1: derived: voicebot
[urllib3:urllib3.connectionpool] Starting new HTTPS connection (1): git.nosapp.it:443
[urllib3:urllib3.connectionpool] https://git.nosapp.it:443 "GET /Voicebot/agents.git/info/refs?service=git-upload-pack HTTP/1.1" 200 172
[urllib3:urllib3.connectionpool] https://git.nosapp.it:443 "POST /Voicebot/agents.git/git-upload-pack HTTP/1.1" 200 None
 1: Version solving took 0.158 seconds.
 1: Tried 1 solutions.

Stack trace:

28  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/application.py:327 in run
     325│ 
     326│             try:
   → 327│                 exit_code = self._run(io)
     328│             except BrokenPipeError:
     329│                 # If we are piped to another process, it may close early and send a

27  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/console/application.py:260 in _run
     258│         with directory(self._working_directory):
     259│             try:
   → 260│                 exit_code = super()._run(io)
     261│             except PoetryRuntimeError as e:
     262│                 io.write_error_line("")

26  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/application.py:431 in _run
     429│             io.input.interactive(interactive)
     430│ 
   → 431│         exit_code = self._run_command(command, io)
     432│         self._running_command = None
     433│ 

25  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/application.py:473 in _run_command
     471│ 
     472│         if error is not None:
   → 473│             raise error
     474│ 
     475│         return terminate_event.exit_code

24  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/application.py:457 in _run_command
     455│ 
     456│             if command_event.command_should_run():
   → 457│                 exit_code = command.run(io)
     458│             else:
     459│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

23  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/commands/base_command.py:117 in run
     115│         io.input.validate()
     116│ 
   → 117│         return self.execute(io) or 0
     118│ 
     119│     def merge_application_definition(self, merge_args: bool = True) -> None:

22  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/console/commands/installer_command.py:39 in execute
      37│     def execute(self, io: IO) -> int:
      38│         PoetryKeyring.preflight_check(io, self.poetry.config)
   →  39│         return super().execute(io)
      40│ 

21  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/cleo/commands/command.py:61 in execute
      59│ 
      60│         try:
   →  61│             return self.handle()
      62│         except KeyboardInterrupt:
      63│             return 1

20  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/console/commands/update.py:58 in handle
      56│         self.installer.update(True)
      57│ 
   →  58│         return self.installer.run()
      59│ 

19  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/installation/installer.py:103 in run
     101│             self.verbose(True)
     102│ 
   → 103│         return self._do_install()
     104│ 
     105│     def dry_run(self, dry_run: bool = True) -> Installer:

18  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/installation/installer.py:241 in _do_install
     239│                 source_root=self._env.path.joinpath("src")
     240│             ):
   → 241│                 solved_packages = solver.solve(
     242│                     use_latest=self._whitelist
     243│                 ).get_solved_packages()

17  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/puzzle/solver.py:87 in solve
      85│         with self._progress(), self._provider.use_latest_for(use_latest or []):
      86│             start = time.time()
   →  87│             packages = self._solve()
      88│             # simplify markers by removing redundant information
      89│             for transitive_info in packages.values():

16  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/puzzle/solver.py:168 in _solve
     166│ 
     167│         try:
   → 168│             result = resolve_version(self._package, self._provider)
     169│ 
     170│             packages = result.packages

15  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/mixology/__init__.py:18 in resolve_version
      16│     solver = VersionSolver(root, provider)
      17│ 
   →  18│     return solver.solve()
      19│ 

14  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/mixology/version_solver.py:174 in solve
     172│             while next is not None:
     173│                 self._propagate(next)
   → 174│                 next = self._choose_package_version()
     175│ 
     176│             return self._result()

13  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/mixology/version_solver.py:572 in _choose_package_version
     570│             package = locked
     571│ 
   → 572│         package = self._provider.complete_package(package)
     573│ 
     574│         conflict = False

12  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/puzzle/provider.py:575 in complete_package
      573│                     if locked is not None and locked.package.is_same_package_as(dep):
      574│                         continue
   →  575│                     self.search_for_direct_origin_dependency(dep)
      576│ 
      577│         dependencies = self._get_dependencies_with_overrides(_dependencies, package)

11  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/puzzle/provider.py:241 in search_for_direct_origin_dependency
      239│         elif dependency.is_vcs():
      240│             dependency = cast("VCSDependency", dependency)
   →  241│             package = self._search_for_vcs(dependency)
      242│ 
      243│         elif dependency.is_file():

10  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/puzzle/provider.py:316 in _search_for_vcs
      314│         and get the information we need by checking out the specified reference.
      315│         """
   →  316│         package = self._direct_origin.get_package_from_vcs(
      317│             dependency.vcs,
      318│             dependency.source,

 9  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/packages/direct_origin.py:116 in get_package_from_vcs
     114│             raise ValueError(f"Unsupported VCS dependency {vcs}")
     115│ 
   → 116│         return _get_package_from_git(
     117│             url=url,
     118│             branch=branch,

 8  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/packages/direct_origin.py:34 in _get_package_from_git
      32│     source_root: Path | None = None,
      33│ ) -> Package:
   →  34│     source = Git.clone(
      35│         url=url,
      36│         source_root=source_root,

 7  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/vcs/git/backend.py:510 in clone
     508│         try:
     509│             if not cls.is_using_legacy_client():
   → 510│                 local = cls._clone(url=url, refspec=refspec, target=target)
     511│                 cls._clone_submodules(repo=local)
     512│                 return local

 6  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/vcs/git/backend.py:307 in _clone
     305│             local = Repo(str(target))
     306│ 
   → 307│         remote_refs = cls._fetch_remote_refs(url=url, local=local)
     308│ 
     309│         logger.debug(

 5  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/poetry/vcs/git/backend.py:239 in _fetch_remote_refs
     237│ 
     238│         with local:
   → 239│             result: FetchPackResult = client.fetch(
     240│                 path,
     241│                 local,

 4  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/dulwich/client.py:981 in fetch
      979│             f, commit, abort = target.object_store.add_pack()
      980│         try:
   →  981│             result = self.fetch_pack(
      982│                 path,
      983│                 determine_wants,

 3  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/dulwich/client.py:2685 in fetch_pack
     2683│         req_data = BytesIO()
     2684│         req_proto = Protocol(None, req_data.write)
   → 2685│         (new_shallow, new_unshallow) = _handle_upload_pack_head(
     2686│             req_proto,
     2687│             negotiated_capabilities,

 2  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/dulwich/client.py:632 in _handle_upload_pack_head
      630│         new_shallow = new_unshallow = set()
      631│ 
   →  632│     have = next(graph_walker)
      633│     while have:
      634│         proto.write_pkt_line(COMMAND_HAVE + b" " + have + b"\n")

 1  ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/dulwich/object_store.py:1477 in next
     1475│             ret = self.heads.pop()
     1476│             try:
   → 1477│                 ps = self.get_parents(ret)
     1478│             except KeyError:
     1479│                 return None

AttributeError

'Tag' object has no attribute 'parents'

at ~/.pyenv/versions/3.12.7/lib/python3.12/site-packages/dulwich/repo.py:346 in get_parents
     342│         if commit_id in self.shallows:
     343│             return []
     344│         if commit is None:
     345│             commit = self.store[commit_id]
  →  346│         return commit.parents
     347│ 
     348│ 
     349│ class BaseRepo:
     350│     """Base class for a git repository.

@IngLP IngLP added kind/bug Something isn't working as expected status/triage This issue needs to be triaged labels Feb 24, 2025
@Secrus
Copy link
Member

Secrus commented Feb 24, 2025

@jelmer This looks like something wrong with the dulwich code. Could you take a look if that's on the dulwich or is this us holding it wrong?

@lcosmin
Copy link

lcosmin commented Feb 24, 2025

I'm experiencing the same error ('Tag' object has no ... ) and I've managed to track it down to the repo name.

This throws the error:

dependencies = [
    "some-dep  @ git+ssh://[email protected]/project/this.causes.trouble.git@master"
]

This doesn't (after renaming the repo):

dependencies = [
    "some-dep  @ git+ssh://[email protected]/project/this-causes-trouble.git@master"
]

So it seems it's the dots in the repo name, at least in my case.

Using poetry 2.1.1.

Later edit:

I did a bit of investigating.
Here's a stack trace when then exception is thrown: https://pastebin.com/RYBijRcH

So, it seems that when the repo name contains dots, the execution flow reaches the get_parents function and specifically this if branch, where commit assigned (was None). And it's assigned a Tag object, which indeed doesn't have a parents attribute.

       344│         if commit is None:
       345│             commit = self.store[commit_id]
    →  346│         return commit.parents

When the repo name contains dashes, the get_parents function is not called at all.

To be clear, I get this exception when I do a poetry update, the dependency was added manually by editing pyproject.toml.

HTH

@IngLP
Copy link
Author

IngLP commented Feb 24, 2025

In my case, I don't even have dashes in repo name.

@lcosmin
Copy link

lcosmin commented Feb 24, 2025

Ok, ignore my comment above. It seems the repository name "fixing" the issue was just a coincidence.

There was something wrong with the code poetry checked out in .venv/src/this.causes.trouble and renaming the repo actually forced it to check it out again.

Problem was solved by removing .venv/src/this.cause.trouble; works with dots now, too.

@dimbleby
Copy link
Contributor

Nevertheless, wiping out .venv/src and retrying may be helpful for OP anyway.

However I see this result:

$ poetry lock
Updating dependencies
Resolving dependencies... (6.0s)

Failed to clone https://github.com/livekit/agents.git at '[email protected]', verify ref exists on remote.

looks like pointing at a tag that doesn't exist?

@jelmer
Copy link
Contributor

jelmer commented Feb 24, 2025

FWIW, this seems to work fine with Dulwich itself:

% dulwich clone https://github.com/livekit/agents.git
Enumerating objects: 56397, done.
Counting objects: 100% (1873/1873), done.
Compressing objects: 100% (694/694), done.
Total 56397 (delta 1526), reused 1234 (delta 1098), pack-reused 54524 (from 2)
copied 56396 pack entries

Though that's not cloning the specific tag, since that - as @dimbleby mentions - doesn't exist (anymore?).

@IngLP
Copy link
Author

IngLP commented Feb 24, 2025

This was just a copy/paste error. I guarantee that I tested with a ref that actually exists. I fixed the issue description.

@dimbleby
Copy link
Contributor

well then I do not reproduce - works fine on my machine

which supports the idea that there is some state on your machine that is for some reason problematic

suggest - as above - removing the existing checkout in your venv (or even the whole env) and trying over.

if you can provide a way to reproduce whatever state you are in then it may be possible to figure out how to avoid getting there. If not, then likely not.

@IngLP
Copy link
Author

IngLP commented Feb 24, 2025

I can confirm deleting and recreating the environment works.
But why? I used the --no-cache option and also poetry cache clear --all . the command.

@dimbleby
Copy link
Contributor

if you can provide a way to reproduce whatever state you are in then it may be possible to figure out how to avoid getting there. If not, then likely not.

@alexpilcher
Copy link

Ah! Thanks @dimbleby and @IngLP for your very timely posts here. I was just wrestling with the same error message and you have pointed me to the very simple solution. 😌

In my case, I was trying to install a tag from a private Git repo I maintain. I had sneakily recreated this tag to correct a mistake, but I had run poetry install before doing so and left a copy of the first version of the tag on my laptop virtual environment. I assumed the dodgy tag history was part of the problem, but I was wasting my time clearing out every Poetry cache I could find and not thinking about the virtual env. 🤦 All good now!

@danodonovan
Copy link

Super helpful thread - thanks. I ended up with an inexplicable 'Tag' object has no attribute 'parents' error. Reading this thread I see it was because I manually changed the tag of a private git repo in pyproject.toml and ran $ poetry lock before that tag existed on the remote. The fix (for me) was

poetry env remove
poetry lock

... the nuclear option 😳 ... but it worked! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working as expected status/triage This issue needs to be triaged
Projects
None yet
Development

No branches or pull requests

7 participants