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

[internal] Add context manager to handle temporary unfreezing of frozen_after_init objects #16863

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/python/pants/util/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from abc import ABC, abstractmethod
from contextlib import contextmanager
from dataclasses import FrozenInstanceError as FrozenInstanceError
from functools import wraps
from typing import Any, Callable, Optional, Type, TypeVar, Union
from typing import Any, Callable, Iterator, Optional, Type, TypeVar, Union

T = TypeVar("T")
C = TypeVar("C", bound=Type)
Expand Down Expand Up @@ -125,6 +126,15 @@ def freeze_instance(self) -> None:
def unfreeze_instance(self) -> None:
self._is_frozen = False

@contextmanager
def unfrozen(self) -> Iterator:
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should name this something like unsafe_unfrozen() or unfrozen_for_tests()? I don't think we want this used in production. While pantsbuild/pants contributors will know better, plugin authors might not.

Copy link
Contributor Author

@chrisjrn chrisjrn Sep 14, 2022

Choose a reason for hiding this comment

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

It's added as _unfrozen, and you need to do cast(Any, frozen_instance)._unfrozen(), so I don't think there's a good chance that people will find this unless they go looking.

old_is_frozen = self._is_frozen
try:
self._is_frozen = False
yield
finally:
self._is_frozen = old_is_frozen

@wraps(prev_init)
def new_init(self, *args: Any, **kwargs: Any) -> None:
prev_init(self, *args, **kwargs)
Expand All @@ -140,6 +150,7 @@ def new_setattr(self, key: str, value: Any) -> None:

cls._freeze_instance = freeze_instance
cls._unfreeze_instance = unfreeze_instance
cls._unfrozen = unfrozen
cls.__init__ = new_init
cls.__setattr__ = new_setattr # type: ignore[assignment]

Expand Down