Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add official support for Python 3.12 #3587

Merged
merged 10 commits into from
Mar 12, 2024
Merged

Add official support for Python 3.12 #3587

merged 10 commits into from
Mar 12, 2024

Conversation

astrojuanlu
Copy link
Member

Close #3287.

Description

Development notes

First attempt, I haven't ran the test suite locally yet. But pip install -e .[test] worked first time on Apple Silicon.

Developer Certificate of Origin

We need all contributions to comply with the Developer Certificate of Origin (DCO). All commits must be signed off by including a Signed-off-by line in the commit message. See our wiki for guidance.

If your PR is blocked due to unsigned commits, then you must follow the instructions under "Rebase the branch" on the GitHub Checks page for your PR. This will retroactively add the sign-off to all unsigned commits and allow the DCO check to pass.

Checklist

  • Read the contributing guidelines
  • Signed off each commit with a Developer Certificate of Origin (DCO)
  • Opened this PR as a 'Draft Pull Request' if it is work-in-progress
  • Updated the documentation to reflect the code changes
  • Added a description of this change in the RELEASE.md file
  • Added tests to cover my changes
  • Checked if this change will affect Kedro-Viz, and if so, communicated that with the Viz team

@astrojuanlu
Copy link
Member Author

Tests failing on 3.11 instead 🤔

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/queues.py", line 244, in _feed
    obj = _ForkingPickler.dumps(obj)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'PluginManager.add_hookcall_monitoring.<locals>.traced_hookexec'

rings a bell but I don't have time to look at this right now, will do so later.

@merelcht
Copy link
Member

merelcht commented Feb 2, 2024

Tests failing on 3.11 instead 🤔

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/queues.py", line 244, in _feed
    obj = _ForkingPickler.dumps(obj)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'PluginManager.add_hookcall_monitoring.<locals>.traced_hookexec'

rings a bell but I don't have time to look at this right now, will do so later.

This is the flaky test that occasionally fails. I think @lrcouto was seeing this as well on her PR for adding the _EPHEMERAL attribute.

@astrojuanlu

This comment was marked as outdated.

@@ -437,7 +438,8 @@ def test_overlapping_patterns(self, tmp_path, mocker):

mocked_load = mocker.patch("omegaconf.OmegaConf.load")
expected_path = (tmp_path / "dev" / "user1" / "catalog2.yml").resolve()
assert mocked_load.called_once_with(expected_path)

mocked_load.assert_called_once_with(expected_path)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See python/cpython#100690

This assert was trivially passing, the test was not doing anything (and it's broken at least in 3.11 and 3.12)

@astrojuanlu
Copy link
Member Author

One test failure left, only happening on Python 3.12:

    @use_config_dir
    def test_load_core_config_get_syntax(self, tmp_path):
        """Make sure core config can be fetched with .get()"""
        conf = OmegaConfigLoader(
            str(tmp_path), base_env=_BASE_ENV, default_run_env=_DEFAULT_RUN_ENV
        )
        params = conf.get("parameters")
        catalog = conf.get("catalog")
    
>       assert params["param1"] == 1
E       TypeError: 'NoneType' object is not subscriptable

@lrcouto
Copy link
Contributor

lrcouto commented Feb 2, 2024

Tests failing on 3.11 instead 🤔

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/queues.py", line 244, in _feed
    obj = _ForkingPickler.dumps(obj)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/multiprocessing/reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'PluginManager.add_hookcall_monitoring.<locals>.traced_hookexec'

rings a bell but I don't have time to look at this right now, will do so later.

This is the flaky test that occasionally fails. I think @lrcouto was seeing this as well on her PR for adding the _EPHEMERAL attribute.

This test is different than the one I've seen. There was one that was caused by a requirement version, which Nok fixed, and another that happened in the tests for the starters. This one is new to me.

@ankatiyar
Copy link
Contributor

One test failure left, only happening on Python 3.12:

    @use_config_dir
    def test_load_core_config_get_syntax(self, tmp_path):
        """Make sure core config can be fetched with .get()"""
        conf = OmegaConfigLoader(
            str(tmp_path), base_env=_BASE_ENV, default_run_env=_DEFAULT_RUN_ENV
        )
        params = conf.get("parameters")
        catalog = conf.get("catalog")
    
>       assert params["param1"] == 1
E       TypeError: 'NoneType' object is not subscriptable

Did a little digging - python/cpython#105524

Close #3287.

Signed-off-by: Juan Luis Cano Rodríguez <juan_luis_cano@mckinsey.com>
Signed-off-by: Juan Luis Cano Rodríguez <juan_luis_cano@mckinsey.com>
@astrojuanlu
Copy link
Member Author

Looks like this will require a bit of work. I'm not pursuing this PR for the time being.

@merelcht
Copy link
Member

Looks like this will require a bit of work. I'm not pursuing this PR for the time being.

@astrojuanlu Maybe you can add some context on the challenges you're seeing in #3287 and then we can properly plan it for a sprint?

@astrojuanlu
Copy link
Member Author

Good point, done #3287 (comment)

Ahdra Merali and others added 4 commits March 8, 2024 13:43
Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Signed-off-by: Ahdra Merali <90615669+AhdraMeraliQB@users.noreply.github.com>
@AhdraMeraliQB AhdraMeraliQB marked this pull request as draft March 8, 2024 14:17
@@ -401,6 +401,7 @@ def test_empty_catalog_file(self, tmp_path):
)["catalog"]
assert catalog == {}

@pytest.mark.xfail(reason="Logic failing")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the test to check for the intended behaviour. However, it fails, and manual testing shows that this is due to the implementation of the OmegaConfigLoader. I would suggest correcting this should be split out into a separate issue to be addressed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't agree with this being addressed in a separate issue, adding the 3.12 support is what's making this fail and thus it should be fixed in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not the move to include 3.12 that's causing this test to fail, but rather it was never truly passing, the previous method call used for the assert was mistyped, leading to a trivial pass. To resolve this requires digging further into the implementation of the OmegaConfigLoader, as it is not behaving as expected, and perhaps never was. See xref.

@AhdraMeraliQB AhdraMeraliQB marked this pull request as ready for review March 8, 2024 14:23
Ahdra Merali added 2 commits March 8, 2024 14:26
Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Comment on lines 29 to 37
# From Python 3.12 __getitem__ isn't called in UserDict.get()
# Use the version from 3.11 and prior
def get(self, key: str, default: Any = None) -> Any:
"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."
try:
return self[key]
except KeyError:
return default

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this issue, the UserDict's get implementation in 3.12 doesn't work for the config loader anymore, so the method is overwritten to use the get function from the previous python versions

Copy link
Contributor

@AhdraMeraliQB AhdraMeraliQB Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will make the comment in the file more clear Done!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be on OmegaConfigLoader or the abstract method? I am slightly confused why get method is needed for OmegaConf.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be on OmegaConfigLoader or the abstract method?

I went for the AbstractConfigLoader to catch any cases where users have defined their own Config Loaders (for whatever reason) that inherit from the AbstractConfigLoader.

I am slightly confused why get method is needed for OmegaConf.

Whilst we don't promote using get over the dict syntax, we have made it available - and it features in our API docs - allowing users to do something like:

conf_loader = OmegaConfigLoader(<...>)
if not conf_loader.get("parameters"):
    parameters = MY_LOCAL_PARAMS

Ultimately, removing get() is a breaking change, which would block adding 3.12 support until the next major release.

Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Signed-off-by: Ahdra Merali <ahdra.merali@quantumblack.com>
Copy link
Member

@merelcht merelcht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @astrojuanlu and @AhdraMeraliQB for making this work 👍

Copy link
Contributor

@ankatiyar ankatiyar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AhdraMeraliQB AhdraMeraliQB merged commit 338736e into main Mar 12, 2024
41 checks passed
@AhdraMeraliQB AhdraMeraliQB deleted the feat/python-3-12 branch March 12, 2024 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add official support for Python 3.12
6 participants