• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenCOMPES / sed / 9636056013

23 Jun 2024 08:01PM UTC coverage: 91.857% (-0.1%) from 91.962%
9636056013

Pull #437

github

web-flow
Merge branch 'main' into v1_feature_branch
Pull Request #437: Upgrade to V1

182 of 183 new or added lines in 41 files covered. (99.45%)

7 existing lines in 2 files now uncovered.

6430 of 7000 relevant lines covered (91.86%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.22
/sed/core/metadata.py
1
"""This is a metadata handler class from the sed package
2
"""
3
from __future__ import annotations
1✔
4

5
import json
1✔
6
from copy import deepcopy
1✔
7
from typing import Any
1✔
8

9
from sed.core.config import complete_dictionary
1✔
10

11

12
class MetaHandler:
1✔
13
    """This class provides methods to manipulate metadata dictionaries,
14
    and give a nice representation of them.
15

16
    Args:
17
        meta (dict, optional): Pre-existing metadata dict. Defaults to None.
18
    """
19

20
    def __init__(self, meta: dict = None) -> None:
1✔
21
        """Constructor.
22

23
        Args:
24
            meta (dict, optional): Pre-existing metadata dict. Defaults to None.
25
        """
26
        self._m = deepcopy(meta) if meta is not None else {}
1✔
27

28
    def __getitem__(self, val: Any) -> Any:
1✔
29
        """Function for getting a value
30

31
        Args:
32
            val (Any): Metadata category key
33

34
        Returns:
35
            Any: The metadata category entry.
36
        """
UNCOV
37
        return self._m[val]
×
38

39
    def __repr__(self) -> str:
1✔
40
        """String representation function as json
41

42
        Returns:
43
            str: Summary string.
44
        """
45
        return json.dumps(self._m, default=str, indent=4)
1✔
46

47
    def _format_attributes(self, attributes: dict, indent: int = 0) -> str:
1✔
48
        """Function to summarize a dictionary as html
49

50
        Args:
51
            attributes (dict): dictionary to summarize
52
            indent (int, optional): Indentation value. Defaults to 0.
53

54
        Returns:
55
            str: Generated html summary.
56
        """
57
        INDENT_FACTOR = 20
1✔
58
        html = ""
1✔
59
        for key, value in attributes.items():
1✔
60
            # Format key
61
            formatted_key = key.replace("_", " ").title()
1✔
62
            formatted_key = f"<b>{formatted_key}</b>"
1✔
63

64
            html += f"<div style='padding-left: {indent * INDENT_FACTOR}px;'>"
1✔
65
            if isinstance(value, dict):
1✔
66
                html += f"<details><summary>{formatted_key} [{key}]</summary>"
1✔
67
                html += self._format_attributes(value, indent + 1)
1✔
68
                html += "</details>"
1✔
69
            elif hasattr(value, "shape"):
1✔
70
                html += f"{formatted_key} [{key}]: {value.shape}"
1✔
71
            else:
72
                html += f"{formatted_key} [{key}]: {value}"
1✔
73
            html += "</div>"
1✔
74
        return html
1✔
75

76
    def _repr_html_(self) -> str:
1✔
77
        """Summary function as html
78

79
        Returns:
80
            str: Generated html summary
81
        """
82
        html = self._format_attributes(self._m)
1✔
83
        return html
1✔
84

85
    @property
1✔
86
    def metadata(self) -> dict:
1✔
87
        """Property returning the metadata dict.
88
        Returns:
89
            dict: Dictionary of metadata.
90
        """
91
        return self._m
1✔
92

93
    def add(
1✔
94
        self,
95
        entry: Any,
96
        name: str,
97
        duplicate_policy: str = "raise",
98
    ) -> None:
99
        """Add an entry to the metadata container
100

101
        Args:
102
            entry: dictionary containing the metadata to add.
103
            name: name of the dictionary key under which to add entry.
104
            duplicate_policy: Control behaviour in case the 'name' key
105
                is already present in the metadata dictionary. Can be any of:
106

107
                    - "raise": raises a DuplicateEntryError.
108
                    - "overwrite": overwrites the previous data with the new one.
109
                    - "merge": If ``entry`` is a dictionary, recursively merges it
110
                      into the existing one, overwriting existing entries. Otherwise
111
                      the same as "overwrite".
112
                    - "append": adds a trailing number, keeping both entries.
113

114
        Raises:
115
            DuplicateEntryError: Raised if an entry already exists.
116
        """
117
        if name not in self._m.keys() or duplicate_policy == "overwrite":
1✔
118
            self._m[name] = deepcopy(entry)
1✔
119
        elif duplicate_policy == "raise":
1✔
120
            raise DuplicateEntryError(
1✔
121
                f"an entry {name} already exists in metadata",
122
            )
123
        elif duplicate_policy == "append":
1✔
124
            i = 0
1✔
125
            while True:
126
                i += 1
1✔
127
                newname = f"{name}_{i}"
1✔
128
                if newname not in self._m.keys():
1✔
129
                    break
1✔
130
            self._m[newname] = deepcopy(entry)
1✔
131

132
        elif duplicate_policy == "merge":
1✔
133
            if isinstance(self._m[name], dict):
1✔
134
                if not isinstance(entry, dict):
1✔
135
                    raise ValueError(
×
136
                        "Cannot merge dictionary with non-dictionary entry!",
137
                    )
138
                complete_dictionary(self._m[name], deepcopy(entry))
1✔
139
            else:
140
                self._m[name] = deepcopy(entry)
1✔
141

142
        else:
143
            raise ValueError(
×
144
                f"could not interpret duplication handling method {duplicate_policy}"
145
                f"Please choose between overwrite,append or raise.",
146
            )
147

148

149
class DuplicateEntryError(Exception):
1✔
150
    """Exception raised when attempting to add a duplicate entry to the metadata container.
151

152
    Attributes:
153
        message -- explanation of the error
154
    """
155

156
    def __init__(self, message: str = "An entry already exists in metadata"):
1✔
157
        self.message = message
1✔
158
        super().__init__(self.message)
1✔
159

160
    def __str__(self):
1✔
161
        return f"{self.__class__.__name__}: {self.message}"
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc