question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItΒ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

KeyAlreadyPresent error when adding atlassian-python-api

See original GitHub issue

Issue

I have an existing project that was working fine with atlassian-python-api at version 3.5.2. Running poetry update resulted in:

  KeyAlreadyPresent

  Key "REPORTS" already exists.

  at /nix/store/jkj0kadrnm5bf2mral3ylkzdbrrf4mwy-python3.9-tomlkit-0.7.0/lib/python3.9/site-packages/tomlkit/container.py:176 in append
      172β”‚                         return self
      173β”‚                     elif current_body_element[0].is_dotted():
      174β”‚                         raise TOMLKitError("Redefinition of an existing table")
      175β”‚                 elif not item.is_super_table():
    β†’ 176β”‚                     raise KeyAlreadyPresent(key)
      177β”‚             elif isinstance(item, AoT):
      178β”‚                 if not isinstance(current, AoT):
      179β”‚                     # Tried to define an AoT after a table with the same name.
      180β”‚                     raise KeyAlreadyPresent(key)

I’m using a private PyPi repo, though, so I created a very simple repro that simply tries poetry add atlassian-python-api on a nearly empty project (linked above), and I get the same error there.

I downloaded the tar file for atlassian-python-api and if I grep for REPORTS I get one single hit from their pyproject.toml file:

/Users/abutler/Downloads/atlassian-python-api-3.12.1/pyproject.toml
171:[tool.pylint.REPORTS]

Full log from the GitHub action run:

Creating virtualenv error-repro-VVz8odaq-py3.9 in /home/runner/.cache/pypoetry/virtualenvs
Using virtualenv: /home/runner/.cache/pypoetry/virtualenvs/error-repro-VVz8odaq-py3.9
PyPI: 167 packages found for atlassian-python-api *
Using version ^3.12.1 for atlassian-python-api

Updating dependencies
Resolving dependencies...
   1: fact: error-repro is 0.1.0
   1: derived: error-repro
   1: fact: error-repro depends on atlassian-python-api (^3.12.1)
   1: fact: error-repro depends on pytest (^5.2)
   1: fact: error-repro depends on pytest (^5.2)
   1: selecting error-repro (0.1.0)
   1: derived: pytest (>=5.2,<6.0)
   1: derived: atlassian-python-api (>=3.12.1,<4.0.0)
PyPI: 15 packages found for pytest >=5.2,<6.0
PyPI: 1 packages found for atlassian-python-api >=3.12.1,<4.0.0
PyPI: Getting info for atlassian-python-api (3.12.1) from PyPI
PyPI: No dependencies found, downloading archives
PyPI: Downloading sdist: atlassian-python-api-3.12.1.tar.gz
   1: Version solving took 0.296 seconds.
   1: Tried 1 solutions.

  Stack trace:

  33  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/console_application.py:131 in run
       129β”‚             parsed_args = resolved_command.args
       130β”‚ 
     β†’ 131β”‚             status_code = command.handle(parsed_args, io)
       132β”‚         except KeyboardInterrupt:
       133β”‚             status_code = 1

  32  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/api/command/command.py:120 in handle
       118β”‚     def handle(self, args, io):  # type: (Args, IO) -> int
       119β”‚         try:
     β†’ 120β”‚             status_code = self._do_handle(args, io)
       121β”‚         except KeyboardInterrupt:
       122β”‚             if io.is_debug():

  31  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/api/command/command.py:171 in _do_handle
       169β”‚         handler_method = self._config.handler_method
       170β”‚ 
     β†’ 171β”‚         return getattr(handler, handler_method)(args, io, self)
       172β”‚ 
       173β”‚     def __repr__(self):  # type: () -> str

  30  ~/.poetry/lib/poetry/_vendor/py3.9/cleo/commands/command.py:92 in wrap_handle
        90β”‚         self._command = command
        91β”‚ 
     β†’  92β”‚         return self.handle()
        93β”‚ 
        94β”‚     def handle(self):  # type: () -> Optional[int]

  29  ~/.poetry/lib/poetry/console/commands/add.py:173 in handle
       171β”‚             self._installer.whitelist([r["name"] for r in requirements])
       172β”‚ 
     β†’ 173β”‚             status = self._installer.run()
       174β”‚         except BaseException:
       175β”‚             # Using BaseException here as some exceptions, eg: KeyboardInterrupt, do not inherit from Exception

  28  ~/.poetry/lib/poetry/installation/installer.py:103 in run
       101β”‚         local_repo = Repository()
       102β”‚ 
     β†’ 103β”‚         return self._do_install(local_repo)
       104β”‚ 
       105β”‚     def dry_run(self, dry_run=True):  # type: (bool) -> Installer

  27  ~/.poetry/lib/poetry/installation/installer.py:235 in _do_install
       233β”‚             )
       234β”‚ 
     β†’ 235β”‚             ops = solver.solve(use_latest=self._whitelist)
       236β”‚         else:
       237β”‚             self._io.write_line("Installing dependencies from lock file")

  26  ~/.poetry/lib/poetry/puzzle/solver.py:65 in solve
        63β”‚         with self._provider.progress():
        64β”‚             start = time.time()
     β†’  65β”‚             packages, depths = self._solve(use_latest=use_latest)
        66β”‚             end = time.time()
        67β”‚ 

  25  ~/.poetry/lib/poetry/puzzle/solver.py:233 in _solve
       231β”‚ 
       232β”‚         try:
     β†’ 233β”‚             result = resolve_version(
       234β”‚                 self._package, self._provider, locked=locked, use_latest=use_latest
       235β”‚             )

  24  ~/.poetry/lib/poetry/mixology/__init__.py:7 in resolve_version
       5β”‚     solver = VersionSolver(root, provider, locked=locked, use_latest=use_latest)
       6β”‚ 
     β†’ 7β”‚     return solver.solve()
       8β”‚ 

  23  ~/.poetry/lib/poetry/mixology/version_solver.py:84 in solve
        82β”‚             while next is not None:
        83β”‚                 self._propagate(next)
     β†’  84β”‚                 next = self._choose_package_version()
        85β”‚ 
        86β”‚             return self._result()

  22  ~/.poetry/lib/poetry/mixology/version_solver.py:400 in _choose_package_version
       398β”‚             version = locked
       399β”‚ 
     β†’ 400β”‚         version = self._provider.complete_package(version)
       401β”‚ 
       402β”‚         conflict = False

  21  ~/.poetry/lib/poetry/puzzle/provider.py:433 in complete_package
       431β”‚             package = DependencyPackage(
       432β”‚                 package.dependency,
     β†’ 433β”‚                 self._pool.package(
       434β”‚                     package.name,
       435β”‚                     package.version.text,

  20  ~/.poetry/lib/poetry/repositories/pool.py:135 in package
       133β”‚             for idx, repo in enumerate(self._repositories):
       134β”‚                 try:
     β†’ 135β”‚                     package = repo.package(name, version, extras=extras)
       136β”‚                 except PackageNotFound:
       137β”‚                     continue

  19  ~/.poetry/lib/poetry/repositories/pypi_repository.py:158 in package
       156β”‚         extras=None,  # type: (Union[list, None])
       157β”‚     ):  # type: (...) -> Package
     β†’ 158β”‚         return self.get_release_info(name, version).to_package(name=name, extras=extras)
       159β”‚ 
       160β”‚     def search(self, query):

  18  ~/.poetry/lib/poetry/repositories/pypi_repository.py:223 in get_release_info
       221β”‚             return PackageInfo.load(self._get_release_info(name, version))
       222β”‚ 
     β†’ 223β”‚         cached = self._cache.remember_forever(
       224β”‚             "{}:{}".format(name, version), lambda: self._get_release_info(name, version)
       225β”‚         )

  17  ~/.poetry/lib/poetry/_vendor/py3.9/cachy/repository.py:174 in remember_forever
       172β”‚             return val
       173β”‚ 
     β†’ 174β”‚         val = value(callback)
       175β”‚ 
       176β”‚         self.forever(key, val)

  16  ~/.poetry/lib/poetry/_vendor/py3.9/cachy/helpers.py:6 in value
       4β”‚ def value(val):
       5β”‚     if callable(val):
     β†’ 6β”‚         return val()
       7β”‚ 
       8β”‚     return val

  15  ~/.poetry/lib/poetry/repositories/pypi_repository.py:224 in <lambda>
       222β”‚ 
       223β”‚         cached = self._cache.remember_forever(
     β†’ 224β”‚             "{}:{}".format(name, version), lambda: self._get_release_info(name, version)
       225β”‚         )
       226β”‚ 

  14  ~/.poetry/lib/poetry/repositories/pypi_repository.py:304 in _get_release_info
       302β”‚                 return data.asdict()
       303β”‚ 
     β†’ 304β”‚             info = self._get_info_from_urls(urls)
       305β”‚ 
       306β”‚             data.requires_dist = info.requires_dist

  13  ~/.poetry/lib/poetry/repositories/pypi_repository.py:419 in _get_info_from_urls
       417β”‚                 return self._get_info_from_wheel(platform_specific_wheels[0])
       418β”‚ 
     β†’ 419β”‚         return self._get_info_from_sdist(urls["sdist"][0])
       420β”‚ 
       421β”‚     def _get_info_from_wheel(self, url):  # type: (str) -> PackageInfo

  12  ~/.poetry/lib/poetry/repositories/pypi_repository.py:447 in _get_info_from_sdist
       445β”‚             self._download(url, str(filepath))
       446β”‚ 
     β†’ 447β”‚             return PackageInfo.from_sdist(filepath)
       448β”‚ 
       449β”‚     def _download(self, url, dest):  # type: (str, str) -> None

  11  ~/.poetry/lib/poetry/inspection/info.py:561 in from_sdist
       559β”‚         """
       560β”‚         if path.is_file():
     β†’ 561β”‚             return cls._from_sdist_file(path=path)
       562β”‚ 
       563β”‚         # if we get here then it is neither an sdist instance nor a file

  10  ~/.poetry/lib/poetry/inspection/info.py:291 in _from_sdist_file
       289β”‚ 
       290β”‚             # now this is an unpacked directory we know how to deal with
     β†’ 291β”‚             new_info = cls.from_directory(path=sdist_dir)
       292β”‚ 
       293β”‚         if not info:

   9  ~/.poetry/lib/poetry/inspection/info.py:530 in from_directory
       528β”‚             order to gather metadata.
       529β”‚         """
     β†’ 530β”‚         project_package = cls._get_poetry_package(path)
       531β”‚         if project_package:
       532β”‚             info = cls.from_package(project_package)

   8  ~/.poetry/lib/poetry/inspection/info.py:439 in _get_poetry_package
       437β”‚         # Note: we ignore any setup.py file at this step
       438β”‚         # TODO: add support for handling non-poetry PEP-517 builds
     β†’ 439β”‚         if PyProjectTOML(path.joinpath("pyproject.toml")).is_poetry_project():
       440β”‚             return Factory().create_poetry(path).package
       441β”‚ 

   7  ~/.poetry/lib/poetry/_vendor/py3.9/poetry/core/pyproject/toml.py:64 in is_poetry_project
       62β”‚         if self.file.exists():
       63β”‚             try:
     β†’ 64β”‚                 _ = self.poetry_config
       65β”‚                 return True
       66β”‚             except PyProjectException:

   6  ~/.poetry/lib/poetry/_vendor/py3.9/poetry/core/pyproject/toml.py:54 in poetry_config
       52β”‚     def poetry_config(self):  # type: () -> Optional[TOMLDocument]
       53β”‚         if self._poetry_config is None:
     β†’ 54β”‚             self._poetry_config = self.data.get("tool", {}).get("poetry")
       55β”‚             if self._poetry_config is None:
       56β”‚                 raise PyProjectException(

   5  /opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/_collections_abc.py:762 in get
        760β”‚         'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
        761β”‚         try:
     β†’  762β”‚             return self[key]
        763β”‚         except KeyError:
        764β”‚             return default

   4  ~/.poetry/lib/poetry/_vendor/py3.9/tomlkit/container.py:559 in __getitem__
       557β”‚             # so we need a proxy to retrieve the proper objects
       558β”‚             # from the parent container
     β†’ 559β”‚             return OutOfOrderTableProxy(self, idx)
       560β”‚ 
       561β”‚         item = self._body[idx][1]

   3  ~/.poetry/lib/poetry/_vendor/py3.9/tomlkit/container.py:699 in __init__
       697β”‚                 table_idx = len(self._tables) - 1
       698β”‚                 for k, v in item.value.body:
     β†’ 699β”‚                     self._internal_container.append(k, v)
       700β”‚                     self._tables_map[k] = table_idx
       701β”‚                     if k is not None:

   2  ~/.poetry/lib/poetry/_vendor/py3.9/tomlkit/container.py:169 in append
       167β”‚ 
       168β”‚                         for k, v in item.value.body:
     β†’ 169β”‚                             current.append(k, v)
       170β”‚ 
       171β”‚                         return self

   1  ~/.poetry/lib/poetry/_vendor/py3.9/tomlkit/items.py:922 in append
        920β”‚             _item = item(_item)
        921β”‚ 
     β†’  922β”‚         self._value.append(key, _item)
        923β”‚ 
        924β”‚         if isinstance(key, Key):

  KeyAlreadyPresent

  Key "REPORTS" already exists.

  at ~/.poetry/lib/poetry/_vendor/py3.9/tomlkit/container.py:175 in append
      171β”‚                         return self
      172β”‚                     elif current_body_element[0].is_dotted():
      173β”‚                         raise TOMLKitError("Redefinition of an existing table")
      174β”‚                 elif not item.is_super_table():
    β†’ 175β”‚                     raise KeyAlreadyPresent(key)
      176β”‚             elif isinstance(item, AoT):
      177β”‚                 if not isinstance(current, AoT):
      178β”‚                     # Tried to define an AoT after a table with the same name.
      179β”‚                     raise KeyAlreadyPresent(key)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
austinbutlercommented, Jul 16, 2021

You can install from my fork to get around this for now.

[tool.poetry.dependencies]
 atlassian-python-api = { git = "https://github.com/austinbutler/atlassian-python-api.git", branch = "7474d6ca08b10552ed1e7655adaaff01b093facb" }

Note though that I branched from master, which has some commits not yet released.

1reaction
austinbutlercommented, Jul 16, 2021

Seems like TOML Kit is tripped up by ['tool.pylint.MESSAGES CONTROL'] in the pyproject.toml. If I change that to [tool.pylint.'MESSAGES CONTROL'] there’s no longer a duplicate table name. Opened a PR atlassian-python-api to β€œfix” that (not intimately familiar with TOML so not entirely sure whether it’s actually invalid). Also created an issue with TOML Kit. Since Poetry is not at fault this can probably be closed. I could close it myself, but not sure if it’s handy to have open in case others end up with the same issue and come here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Srinivas Reddy Thatiparthy - Profile - Bountysource
Srinivas Reddy Thatiparthy commented on this issueKeyAlreadyPresent error when adding atlassian-python-api. poetry 1 year ago.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found