Coverage for glotter/testinfo.py: 100%
74 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-12 02:25 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-12 02:25 +0000
1import yaml
2from jinja2 import Environment, BaseLoader
4from glotter.project import NamingScheme
5from glotter.settings import Settings
8class ContainerInfo:
9 """Configuration for a container to run for a directory"""
11 def __init__(self, image, tag, cmd, build=None):
12 """
13 Initialize a ContainerInfo
15 :param image: the image to run
16 :param tag: the tag of the image to run
17 :param cmd: the command to run the source inside the container
18 :param build: an optional command to run to build the source before running the command
19 """
20 self._image = image
21 self._cmd = cmd
22 self._tag = tag
23 self._build = build
25 @property
26 def image(self):
27 """Returns the image to run"""
28 return self._image
30 @property
31 def cmd(self):
32 """Returns the command to run the source inside the container"""
33 return self._cmd
35 @property
36 def tag(self):
37 """Returns the tag of the image to run"""
38 return self._tag
40 @property
41 def build(self):
42 """Returns the command to build the source before running it inside the container"""
43 return self._build
45 @classmethod
46 def from_dict(cls, dictionary):
47 """
48 Create a ContainerInfo from a dictionary
50 :param dictionary: the dictionary representing ContainerInfo
51 :return: a new ContainerInfo
52 """
53 image = dictionary["image"]
54 tag = dictionary["tag"]
55 cmd = dictionary["cmd"]
56 build = dictionary["build"] if "build" in dictionary else None
57 return ContainerInfo(image=image, tag=tag, cmd=cmd, build=build)
59 def __eq__(self, other):
60 return (
61 self.image == other.image
62 and self.cmd == other.cmd
63 and self.tag == other.tag
64 and self.build == other.build
65 )
68class FolderInfo:
69 """Metadata about sources in a directory"""
71 def __init__(self, extension, naming):
72 """
73 Initialize a FolderInfo
75 :param extension: the file extension that is considered as source
76 :param naming: the naming scheme for files in the directory
77 """
78 self._extension = extension
79 try:
80 self._naming = NamingScheme[naming]
81 except KeyError as e:
82 raise KeyError(f'Unknown naming scheme: "{naming}"') from e
84 @property
85 def extension(self):
86 """Returns the extension for sources in the directory"""
87 return self._extension
89 @property
90 def naming(self):
91 """Returns the naming scheme for the directory"""
92 return self._naming
94 def get_project_mappings(self, include_extension=False):
95 """
96 Uses the naming scheme to generate the expected source names in the directory
97 and create a mapping from ProjectType to source name
99 :param include_extension: whether to include the extension in the source name
100 :return: a dict where the key is a ProjectType and the value is the source name
101 """
102 extension = self.extension if include_extension else ""
103 return {
104 project_type: f"{project.get_project_name_by_scheme(self.naming)}{extension}"
105 for project_type, project in Settings().projects.items()
106 }
108 def __eq__(self, other):
109 return self.extension == other.extension and self.naming == other.naming
111 @classmethod
112 def from_dict(cls, dictionary):
113 """
114 Create a FileInfo from a dictionary
116 :param dictionary: the dictionary representing FileInfo
117 :return: a new FileInfo
118 """
119 return FolderInfo(dictionary["extension"], dictionary["naming"])
122class TestInfo:
123 """an object representation of a testinfo file"""
125 __test__ = False # Indicate this is not a test
127 def __init__(self, container_info, file_info):
128 """
129 Initialize a TestInfo object
131 :param container_info: ContainerInfo object
132 :param file_info: FileInfo object
133 """
134 self._container_info = container_info
135 self._file_info = file_info
137 @property
138 def container_info(self):
139 """Return container info section"""
140 return self._container_info
142 @property
143 def file_info(self):
144 """Return file info section"""
145 return self._file_info
147 @classmethod
148 def from_dict(cls, dictionary):
149 """
150 Create a TestInfo from a dictionary
152 :param dictionary: the dictionary representing TestInfo
153 :return: a new TestInfo
154 """
155 return TestInfo(
156 container_info=ContainerInfo.from_dict(dictionary["container"]),
157 file_info=FolderInfo.from_dict(dictionary["folder"]),
158 )
160 @classmethod
161 def from_string(cls, string, source):
162 """
163 Create a TestInfo from a string. Modify the string using Jinja2 templating. Then parse it as yaml
165 :param string: contents of a testinfo file
166 :param source: a source object to use for jinja2 template parsing
167 :return: a new TestInfo
168 """
169 template = Environment(loader=BaseLoader).from_string(string)
170 template_string = template.render(source=source)
171 info_yaml = yaml.safe_load(template_string)
172 return cls.from_dict(info_yaml)
174 def __eq__(self, other):
175 return (
176 self.container_info == other.container_info
177 and self.file_info == other.file_info
178 )