From 79303dd13fff01bb38fba6b12554b7b5152a40e0 Mon Sep 17 00:00:00 2001 From: Kiyoon Kim <kiyoon@users.noreply.github.com> Date: Wed, 25 Dec 2024 15:00:48 +0900 Subject: [PATCH 1/3] fix(version): exec code with lazy type in dataclass --- backend/src/hatchling/version/source/code.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/hatchling/version/source/code.py b/backend/src/hatchling/version/source/code.py index dc708aee7..92fc7c4a0 100644 --- a/backend/src/hatchling/version/source/code.py +++ b/backend/src/hatchling/version/source/code.py @@ -46,6 +46,7 @@ def get_version_data(self) -> dict: spec = spec_from_file_location(os.path.splitext(path)[0], path) module = module_from_spec(spec) # type: ignore[arg-type] + sys.modules[os.path.splitext(path)[0]] = module old_search_paths = list(sys.path) try: From e09a581a1e61a90e38a8d7c33bea020e2e869f4d Mon Sep 17 00:00:00 2001 From: Kiyoon Kim <kiyoon@users.noreply.github.com> Date: Wed, 25 Dec 2024 15:24:08 +0900 Subject: [PATCH 2/3] docs: PEP 563 with dataclasses fix --- backend/src/hatchling/version/source/code.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/hatchling/version/source/code.py b/backend/src/hatchling/version/source/code.py index 92fc7c4a0..4e611b078 100644 --- a/backend/src/hatchling/version/source/code.py +++ b/backend/src/hatchling/version/source/code.py @@ -46,6 +46,9 @@ def get_version_data(self) -> dict: spec = spec_from_file_location(os.path.splitext(path)[0], path) module = module_from_spec(spec) # type: ignore[arg-type] + + # This fixes using PEP 563 (__future__ annotations) with dataclasses. + # https://github.com/pypa/hatch/issues/1863 sys.modules[os.path.splitext(path)[0]] = module old_search_paths = list(sys.path) From b41b5207dd90dec41d27f9729f55b7761e1b65c5 Mon Sep 17 00:00:00 2001 From: Kiyoon Kim <kiyoon@users.noreply.github.com> Date: Wed, 25 Dec 2024 15:38:23 +0900 Subject: [PATCH 3/3] test: postponed evaluation of annotation with dataclasses --- tests/backend/version/source/test_code.py | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/backend/version/source/test_code.py b/tests/backend/version/source/test_code.py index 1e1cf639e..18c67d1d3 100644 --- a/tests/backend/version/source/test_code.py +++ b/tests/backend/version/source/test_code.py @@ -125,3 +125,65 @@ def foo(version_info): with temp_dir.as_cwd(): assert source.get_version_data()['version'] == '1.0.0.1.dev0' + + +def test_pep563_with_dataclasses_1(temp_dir, helpers): + """ + Test postponed evaluation of annotations (using __future__) with dataclasses. + + References: + - https://github.com/pypa/hatch/issues/1863 + """ + source = CodeSource(str(temp_dir), {'path': 'a/b.py'}) + + file_path = temp_dir / 'a' / 'b.py' + file_path.ensure_parent_dir_exists() + file_path.write_text( + helpers.dedent( + """ + from __future__ import annotations + + from dataclasses import dataclass + + @dataclass + class VersionConfig: + test_dir: str | None = None + verbose: bool = False + + __version__ = "0.1.1" + """ + ) + ) + + with temp_dir.as_cwd(): + assert source.get_version_data()['version'] == '0.1.1' + + +def test_pep563_with_dataclasses_2(temp_dir, helpers): + """ + Test postponed evaluation of annotations (using "type" string) with dataclasses. + + References: + - https://github.com/pypa/hatch/issues/1863 + """ + source = CodeSource(str(temp_dir), {'path': 'a/b.py'}) + + file_path = temp_dir / 'a' / 'b.py' + file_path.ensure_parent_dir_exists() + file_path.write_text( + helpers.dedent( + """ + from dataclasses import dataclass + + @dataclass + class VersionConfig: + test_dir: "str | None" = None + verbose: bool = False + + __version__ = "0.1.1" + """ + ) + ) + + with temp_dir.as_cwd(): + assert source.get_version_data()['version'] == '0.1.1'