'ConfigParser' object has no attribute 'readfp'. Did you mean: 'read'? on Python 3.12

Bug #2041407 reported by Michał Sawicz
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Snapcraft
Fix Released
Undecided
Unassigned
lazr.restfulclient
Fix Released
Undecided
Unassigned

Bug Description

`readfp` is no more since 3.12

https://docs.python.org/3.12/library/configparser.html#configparser.ConfigParser.read_file

```
Traceback (most recent call last):
  File "/home/runner/work/mir-ci/mir-ci/bin/process_snaps.py", line 189, in <module>
    lp = Launchpad.login_with(
         ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/launchpadlib/launchpad.py", line 700, in login_with
    return cls._authorize_token_and_login(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/launchpadlib/launchpad.py", line 445, in _authorize_token_and_login
    cached_credentials = credential_store.load(
                         ^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/launchpadlib/credentials.py", line 345, in load
    return self.do_load(unique_key)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/launchpadlib/credentials.py", line 486, in do_load
    return Credentials.load_from_path(self.filename)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/lazr/restfulclient/authorize/oauth.py", line 218, in load_from_path
    credentials.load(credentials_file)
  File "/opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/lazr/restfulclient/authorize/oauth.py", line 185, in load
    reader = getattr(parser, 'read_file', parser.readfp)
                                          ^^^^^^^^^^^^^
AttributeError: 'ConfigParser' object has no attribute 'readfp'. Did you mean: 'read'?
```

Related branches

Michał Sawicz (saviq)
no longer affects: launchpadlib
description: updated
Revision history for this message
Jürgen Gmach (jugmac00) wrote (last edit ):

Hi Michael,

Thanks for the report!

We will drop Python 2 support for all our packages in the next cycle, that also will include adding support for all modern Python versions.

When did you encounter this issue?

Are you currently blocked on anything, so we'd need to provide a fix sooner than scheduled?

Revision history for this message
Jürgen Gmach (jugmac00) wrote :

Issue can be reproduced by running `tox -e py312` for the `launchpadlib` project.

The latest current release of Ubuntu ships with Python 3.11, so is not affected, but Noble will be affected.

Revision history for this message
Michał Sawicz (saviq) wrote :

> When did you encounter this issue?

Hey, in a GitHub action:

https://github.com/MirServer/mir-ci/actions/runs/6658100512/job/18094238811

It had `python-version: 3.x` there so it installed 3.12.

Revision history for this message
Michał Sawicz (saviq) wrote :

Oh and no, not blocked, just downgraded to 3.11, thanks :)

Revision history for this message
Mateus Rodrigues de Morais (mateus-morais) wrote :

Hi! This issue also surfaced on the python-launchpadlib autopkgtest when running with python 3.12 [1].

python3-defaults just added support for python3.12 on Noble and is currently on proposed, blocked on quite a few issues, including this one for python-launchpadlib [2].

[1] https://autopkgtest.ubuntu.com/results/autopkgtest-noble/noble/amd64/p/python-launchpadlib/20231126_095749_1b093@/log.gz

[2] https://ubuntu-archive-team.ubuntu.com/proposed-migration/update_excuses.html#python3-defaults

Revision history for this message
Mateus Rodrigues de Morais (mateus-morais) wrote (last edit ):

I've written this patch to fix the error.

EDIT: Deleted patch and, after further discussion down below, submitted a Merge Proposal instead.

Revision history for this message
Stefano Rivera (stefanor) wrote :

Can I suggest dropping that getattr line entirely. It looks like old compatibility fallback code.
I'd just use parser.read_file(readable_file)

I'll upload in Debian when there's a patch applied upstream.

Revision history for this message
Mateus Rodrigues de Morais (mateus-morais) wrote :

Given comment #1, would it be an option to invert the getattr logic instead, so that it tries readfp first and fallback to read_file, i.e. reader = getattr(parser, "readfp", parser.read_file)?

I think that would maintain compatibility when readfp is available and would fallback to read_file in 3.12, where only that is available.

I can submit a merge proposal.

Revision history for this message
Stefano Rivera (stefanor) wrote (last edit ):

readfp has existed since 2.7/3.1. The fallback isn't needed.

EDIT: No, this is WRONG

Revision history for this message
Stefano Rivera (stefanor) wrote :

Sorry, That was the wrong way around, read_file isn't in 2.7. We need both.

In 2.7 read_file isn't available, and in 3.12 readfp isn't available.

So the current getattr construct won't work either way. It probably needs a "if hasattr", with 2 branches.

Revision history for this message
Mateus Rodrigues de Morais (mateus-morais) wrote :

That makes sense. Since the fallback attribute of getattr isn't lazily loaded, we'd get the inverse of the error we're getting right now.

I've submitted a Merge Proposal using hasattr to safely fallback to readfp when read_file isn't available. This should maintain compatibility and avoid any AttributeErrors.

Simone Pelosi (pelpsi)
Changed in lazr.restfulclient:
status: New → Fix Committed
Simone Pelosi (pelpsi)
Changed in lazr.restfulclient:
status: Fix Committed → Fix Released
Revision history for this message
Michał Sawicz (saviq) wrote :

The snapcraft bit of this is brew / macOS, being fixed here:

https://github.com/Homebrew/homebrew-core/pull/160935

Changed in snapcraft:
status: New → Fix Committed
Michał Sawicz (saviq)
Changed in snapcraft:
status: Fix Committed → Fix Released
Revision history for this message
Grizzly(Francis Smit) (grizzly-smit) wrote :

I cannot do a partial upgrade due to this error if I edit that line I get an error due to check sum fail

Revision history for this message
Grizzly(Francis Smit) (grizzly-smit) wrote :
Download full text (3.1 KiB)

sudo update-manager

(update-manager:211505): dconf-WARNING **: 23:49:21.408: failed to commit changes to dconf: Failed to execute child process “dbus-launch” (No such file or directory)

(update-manager:211505): dconf-WARNING **: 23:49:21.409: failed to commit changes to dconf: Failed to execute child process “dbus-launch” (No such file or directory)

(update-manager:211505): libunity-CRITICAL **: 23:49:21.419: file unity-launcher.c: line 1638: unexpected error: Failed to execute child process “dbus-launch” (No such file or directory) (g-exec-error-quark, 8)

(update-manager:211505): libunity-CRITICAL **: 23:49:21.419: unity_launcher_entry_dbus_impl_construct: assertion 'conn != NULL' failed

(update-manager:211505): libunity-CRITICAL **: 23:49:21.423: unity-inspector.vala:96: Unable to connect to session bus: Failed to execute child process “dbus-launch” (No such file or directory)
warning: could not initiate dbus
/usr/lib/python3/dist-packages/uaclient/apt.py:288: Warning: W:Unable to read /var/lib/ubuntu-advantage/apt-esm/etc/apt/apt.conf.d/ - DirectoryExists (2: No such file or directory)
  apt_pkg.init()
/usr/lib/python3/dist-packages/uaclient/apt.py:270: Warning: W:Unable to read /var/lib/ubuntu-advantage/apt-esm/etc/apt/preferences.d/ - DirectoryExists (2: No such file or directory)
  apt_pkg.init_system()
ERROR:root:not handled exception:
Traceback (most recent call last):

  File "/usr/lib/ubuntu-release-upgrader/do-partial-upgrade", line 114, in <module>
    controller.doPartialUpgrade()

  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 2609, in doPartialUpgrade
    self.prepare()

  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 465, in prepare
    if not self._pythonSymlinkCheck():
           ^^^^^^^^^^^^^^^^^^^^^^^^^^

  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 415, in _pythonSymlinkCheck
    config.readfp(f)
    ^^^^^^^^^^^^^

AttributeError: 'ConfigParser' object has no attribute 'readfp'. Did you mean: 'read'?

Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeViewGtk3.py", line 540, in _handleException
    apport_crash(type, value, tb)
  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeApport.py", line 57, in apport_crash
    apport_excepthook(type, value, tb)
TypeError: apport_excepthook() missing 1 required positional argument: 'exc_tb'

Original exception was:
Traceback (most recent call last):
  File "/usr/lib/ubuntu-release-upgrader/do-partial-upgrade", line 114, in <module>
    controller.doPartialUpgrade()
  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 2609, in doPartialUpgrade
    self.prepare()
  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 465, in prepare
    if not self._pythonSymlinkCheck():
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/DistUpgrade/DistUpgradeController.py", line 415, in _pythonSymlinkCheck
    config.readfp(f)
    ^^^^^^^^^^^^^
AttributeError: 'ConfigParser' object has no attribute 'readfp'. Did you mean: ...

Read more...

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.