Repository navigation
Expand file tree
/
Copy pathhatch_custom_hook.py
More file actions
87 lines (74 loc) · 3.72 KB
/
Copy pathhatch_custom_hook.py
File metadata and controls
87 lines (74 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
from __future__ import annotations
import os
import shutil
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
from typing import Any
import json
class HatchCustomBuildHook(BuildHookInterface):
"""
This class implements Hatch's [custom build hook] (https://hatch.pypa.io/1.6/plugins/build-hook/custom/)
for a copy_version_py operation that copies the _version.py file generated by the hatch-vcs build hook into
specified destination directories. See the `[[tool.hatch.build.hooks.custom]]` section in `pyproject.toml`.
"""
def _validate_config(self):
if sorted(self.config) != ["copy_version_py", "path"] or list(
self.config["copy_version_py"]
) != ["destinations"]:
raise RuntimeError(
"Configuration of the custom build hook must be like { 'copy_version_py': {'destinations': ['path1', ...]}}."
+ f" Received:\n{self.config}"
)
def _compile_translations(self):
"""
Generates types for translation strings based on the English translation JSON file. The types
give feedback during development and validation during linting that all translated strings are
part of the translation files.
"""
translations_dir = os.path.join(
self.root, "src", "deadline", "client", "ui", "translations", "locales"
)
# Load en_US as the source for type generation. The encoding must be explicit: several keys
# contain non-ASCII characters (e.g. the U+2022 bullet), and on Windows the default encoding
# is cp1252, which mis-decodes them into mojibake. That produces a Literal that no longer
# matches the string in the source, so mypy rejects every tr() call using those keys.
en_file = os.path.join(translations_dir, "en_US.json")
with open(en_file, encoding="utf-8") as f:
translations = json.load(f)
# Generate type hints file
keys = list(translations.keys())
# Escape for Python string literals: backslashes, quotes, newlines
escaped_keys = [
k.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n") for k in keys
]
type_file = os.path.join(
self.root, "src", "deadline", "client", "ui", "_translation_keys.py"
)
with open(type_file, "w", encoding="utf-8") as f:
f.write("# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n")
f.write("# Auto-generated from locales/en_US.json - DO NOT EDIT\n\n")
f.write("from typing import Literal\n\n")
f.write("TranslationKey = Literal[\n")
f.write(",\n".join(f' "{k}"' for k in escaped_keys))
f.write("\n]\n")
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
self._validate_config()
self._compile_translations()
for destination in self.config["copy_version_py"]["destinations"]:
print(f"Copying _version.py to {destination}")
shutil.copy(
os.path.join(self.root, "_version.py"),
os.path.join(self.root, destination),
)
def clean(self, versions: list[str]) -> None:
self._validate_config()
cleaned_count = 0
for destination in self.config["copy_version_py"]["destinations"]:
print(f"Cleaning _version.py from {destination}")
clean_path = os.path.join(self.root, destination, "_version.py")
try:
os.remove(clean_path)
cleaned_count += 1
except FileNotFoundError:
pass
print(f"Cleaned {cleaned_count} items")