Coverage for hdl_registers/generator/python/pickle.py: 96%

27 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-04 20:52 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the hdl-registers project, an HDL register generator fast enough to run 

5# in real time. 

6# https://hdl-registers.com 

7# https://github.com/hdl-registers/hdl-registers 

8# -------------------------------------------------------------------------------------------------- 

9 

10import pickle 

11from pathlib import Path 

12from typing import Any 

13 

14from tsfpga.system_utils import create_directory 

15 

16from hdl_registers.generator.register_code_generator import RegisterCodeGenerator 

17from hdl_registers.register_list import RegisterList 

18 

19 

20class PythonPickleGenerator(RegisterCodeGenerator): 

21 """ 

22 Generate a Python pickle of the :class:`.RegisterList` object, along with a Python 

23 module to re-create the pickle in a simple way. 

24 

25 See the :ref:`generator_python` article for usage details. 

26 """ 

27 

28 __version__ = "1.0.0" 

29 

30 SHORT_DESCRIPTION = "Python pickle" 

31 

32 COMMENT_START = "#" 

33 

34 @property 

35 def output_file(self) -> Path: 

36 """ 

37 Result will be placed in this file. 

38 """ 

39 return self.output_folder / f"{self.name}.py" 

40 

41 def __init__(self, register_list: RegisterList, output_folder: Path) -> None: 

42 super().__init__(register_list=register_list, output_folder=output_folder) 

43 

44 self.pickle_file = self.output_folder / f"{self.name}.pickle" 

45 

46 def create( 

47 self, 

48 **kwargs: Any, # noqa: ANN401 

49 ) -> Path: 

50 """ 

51 Create the binary pickle also, apart from the class file. 

52 

53 Note that this is a little bit hacky, preferably each generator should produce only 

54 one file. 

55 """ 

56 # Create directory if it does not exist, but do not delete anything if it does. 

57 create_directory(self.output_folder, empty=False) 

58 

59 with self.pickle_file.open("wb") as file_handle: 

60 pickle.dump(self.register_list, file_handle) 

61 

62 return super().create(**kwargs) 

63 

64 def get_code( 

65 self, 

66 **kwargs: Any, # noqa: ANN401, ARG002 

67 ) -> str: 

68 """ 

69 Save register list object to binary file (pickle) and create a python class 

70 that recreates it. 

71 """ 

72 class_name = self.to_pascal_case(self.name) 

73 

74 return f'''\ 

75import pickle 

76from pathlib import Path 

77from typing import TYPE_CHECKING 

78 

79if TYPE_CHECKING: 

80 from hdl_registers.register_list import RegisterList 

81 

82THIS_DIR = Path(__file__).parent 

83PICKLE_FILE = THIS_DIR / "{self.pickle_file.name}" 

84 

85 

86class {class_name}: 

87 """ 

88 Instantiate this class to get the ``RegisterList`` object for the 

89 ``{self.name}`` register list. 

90 """ 

91 

92 def __new__(cls): 

93 """ 

94 Recreate the ``RegisterList`` object from binary pickle. 

95 """ 

96 with PICKLE_FILE.open("rb") as file_handle: 

97 return pickle.load(file_handle) 

98 

99 

100def get_register_list() -> "RegisterList": 

101 """ 

102 Return a ``RegisterList`` object with the registers/constants from the 

103 ``{self.name}`` register list. 

104 Recreated from a Python pickle file. 

105 """ 

106 with PICKLE_FILE.open("rb") as file_handle: 

107 return pickle.load(file_handle) 

108''' 

109 

110 @property 

111 def should_create(self) -> bool: 

112 """ 

113 Since this generator creates two files, where one is binary, it is impossible to do the 

114 version/hash check. 

115 Hence, set it to "always create". 

116 The mechanism "create if needed" should not be used for this generator anyway, since 

117 this generator is not designed to run in real-time like e.g. the VHDL generator. 

118 """ 

119 return True