Skip to content

Non-working code in update() method of weakref.WeakKeyDictionary #124748

@ri-gilfanov

Description

@ri-gilfanov

Bug report

Bug description:

Edited at 2024.09.30 10:07 AM.

Example of code

import weakref

d = weakref.WeakKeyDictionary()
d.update(x=1)

Traceback

Traceback (most recent call last):
  File "/home/username/example.py", line 4, in <module>
    d.update(x=1)
    ~~~~~~~~^^^^^
  File "/home/username/.pyenv/versions/3.13.0rc2/lib/python3.13/weakref.py", line 518, in update
    self.update(kwargs)
    ~~~~~~~~~~~^^^^^^^^
  File "/home/username/.pyenv/versions/3.13.0rc2/lib/python3.13/weakref.py", line 516, in update
    d[ref(key, self._remove)] = value
      ~~~^^^^^^^^^^^^^^^^^^^
TypeError: cannot create weak reference to 'str' object

Source of error

class WeakKeyDictionary(_collections_abc.MutableMapping):
    ...
    def update(self, dict=None, /, **kwargs):  # `kwargs` always use 'str' for keys
        d = self.data
        if dict is not None:
            if not hasattr(dict, "items"):
                dict = type({})(dict)
            for key, value in dict.items():
                d[ref(key, self._remove)] = value
        if len(kwargs): # If true, then `kwargs` contains a key of `str` type
            self.update(kwargs)  # So this line always raises `TypeError`

Proposals

Option 1

a) Add a clear exception and delete last two lines:

class WeakKeyDictionary(_collections_abc.MutableMapping):
    ...
    def update(self, dict=None, /, **kwargs):
        if kwargs:
            raise TypeError(
                "Keyword arguments are not supported. "
                "Can not create weak references to `str` keys."
            )
          d = self.data
        if dict is not None:
            if not hasattr(dict, "items"):
                dict = type({})(dict)
            for key, value in dict.items():
                d[ref(key, self._remove)] = value

b) Write about this behavior in the documentation.

Option 2

a) Remove the kwargs parameter from WeakKeyDicionary.update().
b) Inherit WeakKeyDicionary from Mapping to avoid violating of the Liskov Substitution Principle with MutableMapping.

class WeakKeyDictionary(_collections_abc.Mapping):
    ...
    def update(self, dict=None):
        d = self.data
        if dict is not None:
            if not hasattr(dict, "items"):
                dict = type({})(dict)
            for key, value in dict.items():
                d[ref(key, self._remove)] = value

Thanks

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions