Skip to content

Fix __str__ call for all Python objects #342

Description

@tooruu

boost::python::object utf8Text = o.attr("__str__")();

Naively calling __str__() on an object assumes it is bound, which is not the case for non-instantiated classes.
Would it be possible to use Python's str builtin?

Activity

  1. Ekopalypse commented on Jul 11, 2024

    @Ekopalypse
    Contributor

    Can you explain when this is a problem when using PythonScript?

  2. tooruu commented on Jul 11, 2024

    @tooruu
    Author

    Can you explain when this is a problem when using PythonScript?

    Let's take editor.write for example. Its C++ signature expects a boost::python::api::object.
    As I understand, we can pass any Python object and you convert it to string via ScintillaWrapper::getStringFromObject by calling o.__str__().
    This works because you usually pass an instantiated class object, meaning you don't need to manually pass self to its methods (like __str__), so a call without arguments works.
    But it breaks if you pass an uninstantiated class object (class itself). It doesn't bind self, so it expects you to pass something to the __str__ method.

    >>> editor.write('text')  # 'text'.__str__() == 'text'
    >>> editor.write(42)  # (42).__str__() == '42'

    So far it looks fine with instances of str and int class (return values are omitted for brevity). Let's try a custom class.

    >>> class Foo:
    ...     def __str__(self):
    ...         return __class__.__name__.lower()
    ...
    >>> editor.write(Foo())  # Foo().__str__() == 'foo'
    >>> editor.write(Foo)  # There is no `self` to auto insert into the `__str__` call.
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    TypeError: Foo.__str__() missing 1 required positional argument: 'self'

    One might expect the value of str(Foo) to be written into the editor, but it wants us to pass something to __str__.

    P.S. In this example str(Foo) == "<class '__main__.Foo'>". Not the most common use case, but you never know what the user is up to!

    >>> class Meta(type):
    ...     def __str__(cls):
    ...         return cls.__name__.upper()
    ... 
    >>> class Bar(metaclass=Meta):
    ...     pass
    ... 
    >>> str(Bar)
    'BAR'
    >>> editor.write(Bar)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    TypeError: descriptor '__str__' of 'object' object needs an argument
  3. Ekopalypse commented on Jul 12, 2024

    @Ekopalypse
    Contributor

    I understand what you mean, but usually PythonScript is used to manipulate Notepad++, Scintilla and the buffer content, but

    but you never know what the user is up to!

    I guess you're right

  4. tooruu commented on Jul 12, 2024

    @tooruu
    Author

    This isn't high priority, or might not even get addressed. Regardless, it is a bug so I had to bring it to your attention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions