Coverage for .nox/test-3-9/lib/python3.9/site-packages/nskit/mixer/components/folder.py: 96%
77 statements
« prev ^ index » next coverage.py v7.4.2, created at 2024-02-25 17:38 +0000
« prev ^ index » next coverage.py v7.4.2, created at 2024-02-25 17:38 +0000
1"""Folder component."""
2from pathlib import Path
3from typing import Any, Dict, List, Optional, Union
5from pydantic import Field, field_validator
7from .file import File
8from .filesystem_object import FileSystemObject
11class Folder(FileSystemObject):
12 """Folder component."""
14 contents: List[Union[File, 'Folder']] = Field(default_factory=list, description='The folder contents')
16 def write(self, base_path: Path, context: Dict[str, Any], override_path: Optional[Path] = None):
17 """Write the rendered content to the appropriate path within the ``base_path``."""
18 folder_path = self.get_path(base_path, context, override_path)
19 folder_path.mkdir(exist_ok=True, parents=True)
20 contents_dict = {}
21 for obj in self.contents:
22 contents_dict.update(obj.write(folder_path, context))
23 return {folder_path: contents_dict}
25 def dryrun(self, base_path: Path, context: Dict[str, Any], override_path: Optional[Path] = None):
26 """Preview the file contents using the context."""
27 folder_path = self.get_path(base_path, context, override_path)
28 contents_dict = {}
29 for u in self.contents:
30 contents_dict.update(u.dryrun(folder_path, context))
31 result = {folder_path: contents_dict}
32 return result
34 def validate(self, base_path: Path, context: Dict[str, Any], override_path: Optional[Path] = None):
35 """Validate the output against expected."""
36 missing = []
37 errors = []
38 ok = []
39 path = self.get_path(base_path, context, override_path)
40 if not path.exists():
41 missing.append(path)
42 for child in self.contents:
43 child_missing, child_errors, child_ok = child.validate(path, context)
44 missing += child_missing
45 errors += child_errors
46 ok += child_ok
47 if not missing and not errors:
48 ok.append(path)
49 return missing, errors, ok
51 @field_validator('contents', mode='before')
52 @classmethod
53 def _validate_contents_ids_unique(cls, contents):
54 if contents:
55 ids_ = []
56 for item in contents:
57 id_ = None
58 if isinstance(item, FileSystemObject):
59 id_ = item.id_
60 if isinstance(item, dict):
61 id_ = item.get('id_', None)
62 if id_ is None:
63 # No id_ provided
64 continue
65 if id_ in ids_:
66 raise ValueError(f'IDs for contents must be unique. The ID({id_}) already exists in the folder contents')
67 ids_.append(id_)
68 return contents
70 def index(self, name_or_id):
71 """Get the index of a specific file or folder given the name (or ID)."""
72 for i, item in enumerate(self.contents):
73 if item.id_ == name_or_id or item.name == name_or_id:
74 return i
75 raise KeyError(f'Name or id_ {name_or_id} not found in contents')
77 def __getitem__(self, name_or_id):
78 """Get the item by name or id."""
79 index = self.index(name_or_id)
80 return self.contents[index]
82 def __setitem__(self, name_or_id, value):
83 """Set an item by name or id."""
84 try:
85 index = self.index(name_or_id)
86 self.contents.pop(index)
87 self.contents.insert(index, value)
88 except KeyError:
89 self.contents.append(value)
91 def _repr(self, context=None, indent=0, **kwargs): # noqa: U100
92 """Represent the contents of the folder."""
93 indent_ = ' '*indent
94 line_start = f'\n{indent_}|- '
95 contents_repr = ''
96 if self.contents:
97 contents = sorted(self.contents, key=lambda x: isinstance(x, Folder))
98 lines = [u._repr(context=context, indent=indent+2) for u in contents]
99 contents_repr = ':'+line_start.join(['']+lines)
100 return f'{super()._repr(context=context)}{contents_repr}'