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

27 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 11:11 +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 

10# ruff: noqa: A005 

11 

12import pickle 

13from pathlib import Path 

14from typing import Any 

15 

16from tsfpga.system_utils import create_directory 

17 

18from hdl_registers.generator.register_code_generator import RegisterCodeGenerator 

19from hdl_registers.register_list import RegisterList 

20 

21 

22class PythonPickleGenerator(RegisterCodeGenerator): 

23 """ 

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

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

26 

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

28 """ 

29 

30 __version__ = "1.0.0" 

31 

32 SHORT_DESCRIPTION = "Python pickle" 

33 

34 COMMENT_START = "#" 

35 

36 @property 

37 def output_file(self) -> Path: 

38 """ 

39 Result will be placed in this file. 

40 """ 

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

42 

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

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

45 

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

47 

48 def create( 

49 self, 

50 **kwargs: Any, # noqa: ANN401 

51 ) -> Path: 

52 """ 

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

54 

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

56 one file. 

57 """ 

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

59 create_directory(self.output_folder, empty=False) 

60 

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

62 pickle.dump(self.register_list, file_handle) 

63 

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

65 

66 def get_code( 

67 self, 

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

69 ) -> str: 

70 """ 

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

72 that recreates it. 

73 """ 

74 class_name = self.to_pascal_case(self.name) 

75 

76 return f'''\ 

77import pickle 

78from pathlib import Path 

79from typing import TYPE_CHECKING 

80 

81if TYPE_CHECKING: 

82 from hdl_registers.register_list import RegisterList 

83 

84THIS_DIR = Path(__file__).parent 

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

86 

87 

88class {class_name}: 

89 """ 

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

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

92 """ 

93 

94 def __new__(cls): 

95 """ 

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

97 """ 

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

99 return pickle.load(file_handle) 

100 

101 

102def get_register_list() -> "RegisterList": 

103 """ 

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

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

106 Recreated from a Python pickle file. 

107 """ 

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

109 return pickle.load(file_handle) 

110''' 

111 

112 @property 

113 def should_create(self) -> bool: 

114 """ 

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

116 version/hash check. 

117 Hence, set it to "always create". 

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

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

120 """ 

121 return True