Skip to content

Deprecate undocumented io.OpenWrapper and _pyio.OpenWrapper #87846

Description

@vstinner
BPO 43680
Nosy @gvanrossum, @vstinner, @tiran, @methane, @serhiy-storchaka
PRs
  • bpo-43680: Remove undocumented io.OpenWrapper #25114
  • bpo-43680: _pyio.open() becomes a static method #25354
  • bpo-43680: Deprecate io.OpenWrapper #25357
  • bpo-43680: Remove _pyio.DocDescriptor. #25395
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2021-04-14.01:26:31.500>
    created_at = <Date 2021-03-31.12:59:21.814>
    labels = ['library', '3.10']
    title = 'Deprecate undocumented io.OpenWrapper and _pyio.OpenWrapper'
    updated_at = <Date 2021-04-14.01:26:31.499>
    user = 'https://github.com/vstinner'

    bugs.python.org fields:

    activity = <Date 2021-04-14.01:26:31.499>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2021-04-14.01:26:31.500>
    closer = 'vstinner'
    components = ['Library (Lib)']
    creation = <Date 2021-03-31.12:59:21.814>
    creator = 'vstinner'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 43680
    keywords = ['patch']
    message_count = 8.0
    messages = ['389896', '389897', '389899', '389902', '389912', '389913', '390828', '391025']
    nosy_count = 5.0
    nosy_names = ['gvanrossum', 'vstinner', 'christian.heimes', 'methane', 'serhiy.storchaka']
    pr_nums = ['25114', '25354', '25357', '25395']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue43680'
    versions = ['Python 3.10']

    Linked PRs

    Activity

    1. vstinner commented on Mar 31, 2021

      @vstinner
      MemberAuthor

      The OpenWrapper function of io and _pyio is an undocumented hack allowing to use the builtin open() function as a method:

      class MyClass:
          method = open
      
      MyClass.method(...)    # class method
      MyClass().method(...)  # instance method

      It is only needed by the _pyio module: the pure Python implementation of the io module:
      ---

      class DocDescriptor:
          """Helper for builtins.open.__doc__
          """
          def __get__(self, obj, typ=None):
              return (
                  "open(file, mode='r', buffering=-1, encoding=None, "
                       "errors=None, newline=None, closefd=True)\n\n" +
                  open.__doc__)
      
      class OpenWrapper:
          """Wrapper for builtins.open
      Trick so that open won't become a bound method when stored
      as a class variable (as dbm.dumb does).
      
      See initstdio() in [Python/pylifecycle.c](https://github.com/python/cpython/blob/main/Python/pylifecycle.c).
      """
      __doc__ = DocDescriptor()
      
          def __new__(cls, *args, **kwargs):
              return open(*args, **kwargs)

      The io module simply uses an alias to open:
      ---

      OpenWrapper = _io.open # for compatibility with _pyio

      No wrapper is needed since built-in functions can be used directly as methods. Example:
      ---

      class MyClass:
          method = len  # built-in function
      
      print(MyClass.method("abc"))
      print(MyClass().method("abc"))

      This example works as expected, it displays "3" two times.

      I propose to simply remove io.OpenWrapper and force developers to explicitly use staticmethod:

      class MyClass:
          method = staticmethod(open)

      io.OpenWrapper is not documented.

      I don't understand the remark about dbm.dumb: I fail to see where the built-in open() function is used as a method.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      on Mar 31, 2021
    3. vstinner commented on Mar 31, 2021

      @vstinner
      MemberAuthor

      I also opened a discussion on python-dev about OpenWrapper and staticmethod:
      https://mail.python.org/archives/list/python-dev@python.org/thread/QZ7SFW3IW3S2C5RMRJZOOUFSHHUINNME/

    4. serhiy-storchaka commented on Mar 31, 2021

      @serhiy-storchaka
      Member

      As for dbm.dumb, it was an attempt to make _Database._commit() working at the shutdown stage (it is indirectly called from __del__()). See bpo-723231. Although in Python 2 __builtin__.open != io.open, and in Python 3.0 the code already uses io.open directly.

      I afraid that this code is not reliable (and never was reliable), because modules os and io can be cleared before calling it, so os.unlink and io.open would not work. But this is a different issue.

    5. serhiy-storchaka commented on Mar 31, 2021

      @serhiy-storchaka
      Member

      OpenWrapper was added in ce3a72a (bpo-1267) and was only used to set __builtin__.open (I suppose that at thet moment dumbdbm.py still set open as a class attribute).

      It is still can be set as a class attribute in user code, so I think that removing OpenWrapper needs a deprecated period.

    6. vstinner commented on Mar 31, 2021

      @vstinner
      MemberAuthor

      OpenWrapper was added in ce3a72a (bpo-1267) and was only used to set __builtin__.open

      It is useless in CPython, since CPython always use the C implementation of the io module, and in the io module, io.OpenWrapper is just an alias to io.open.

      $ python3
      Python 3.9.2 (default, Feb 20 2021, 00:00:00) 
      >>> import io
      >>> io.OpenWrapper is io.open
      True

      (I suppose that at thet moment dumbdbm.py still set open as a class attribute).

      I failed to find where in Lib/dbm/dumb.py the open() function is used to define a method. Maybe the code changed since OpenWrapper was added?

      At commit ce3a72a, the io module was only implemented in Python (Lib/io.py, _io exist didn't exist). It was reimplemented in C in Python 3.1.

    7. vstinner commented on Mar 31, 2021

      @vstinner
      MemberAuthor

      It is still can be set as a class attribute in user code, so I think that removing OpenWrapper needs a deprecated period.

      I'm fine with deprecating the function by defining a __getattr__() function in io.py and _pyio.py. But only if it doesn't block the implementation of the PEP-597 ;-) The PEP-597 implementation issue is discussed at:
      https://bugs.python.org/issue43510#msg389822

    8. vstinner commented on Apr 12, 2021

      @vstinner
      MemberAuthor

      New changeset 77d668b by Victor Stinner in branch 'master':
      bpo-43680: _pyio.open() becomes a static method (GH-25354)
      77d668b

    9. vstinner commented on Apr 14, 2021

      @vstinner
      MemberAuthor

      New changeset 3bc694d by Victor Stinner in branch 'master':
      bpo-43680: Deprecate io.OpenWrapper (GH-25357)
      3bc694d

    10. changed the title [-]Remove undocumented io.OpenWrapper and _pyio.OpenWrapper[/-] [+]Deprecate undocumented io.OpenWrapper and _pyio.OpenWrapper[/+] on Apr 14, 2021
    11. changed the title [-]Remove undocumented io.OpenWrapper and _pyio.OpenWrapper[/-] [+]Deprecate undocumented io.OpenWrapper and _pyio.OpenWrapper[/+] on Apr 14, 2021
    12. transferred this issue fromon Apr 10, 2022
    13. added 4 commits that reference this issue on Nov 6, 2024
    14. encukou commented on Nov 6, 2024

      @encukou
      Member

      This can make test___all__ fail, see #126478.

    15. added a commit that references this issue on Nov 6, 2024
    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

      3.10 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directory

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions