1"""Exception classes for jenkins_jobs errors"""
2
3import inspect
4
5
6def is_sequence(arg):
7    return not hasattr(arg, "strip") and (
8        hasattr(arg, "__getitem__") or hasattr(arg, "__iter__")
9    )
10
11
12class JenkinsJobsException(Exception):
13    pass
14
15
16class ModuleError(JenkinsJobsException):
17    def get_module_name(self):
18        frame = inspect.currentframe()
19        co_name = frame.f_code.co_name
20        module_name = "<unresolved>"
21        while frame and co_name != "run":
22            # XML generation called via dispatch
23            if co_name == "dispatch":
24                data = frame.f_locals
25                module_name = "%s.%s" % (data["component_type"], data["name"])
26                break
27            # XML generation done directly by class using gen_xml or root_xml
28            if co_name == "gen_xml" or co_name == "root_xml":
29                data = frame.f_locals["data"]
30                module_name = next(iter(data.keys()))
31                break
32            frame = frame.f_back
33            co_name = frame.f_code.co_name
34
35        return module_name
36
37
38class InvalidAttributeError(ModuleError):
39    def __init__(self, attribute_name, value, valid_values=None):
40        message = "'{0}' is an invalid value for attribute {1}.{2}".format(
41            value, self.get_module_name(), attribute_name
42        )
43
44        if is_sequence(valid_values):
45            message += "\nValid values include: {0}".format(
46                ", ".join("'{0}'".format(value) for value in valid_values)
47            )
48
49        super(InvalidAttributeError, self).__init__(message)
50
51
52class MissingAttributeError(ModuleError):
53    def __init__(self, missing_attribute, module_name=None):
54        module = module_name or self.get_module_name()
55        if is_sequence(missing_attribute):
56            message = "One of {0} must be present in '{1}'".format(
57                ", ".join("'{0}'".format(value) for value in missing_attribute), module
58            )
59        else:
60            message = "Missing {0} from an instance of '{1}'".format(
61                missing_attribute, module
62            )
63
64        super(MissingAttributeError, self).__init__(message)
65
66
67class AttributeConflictError(ModuleError):
68    def __init__(self, attribute_name, attributes_in_conflict, module_name=None):
69        module = module_name or self.get_module_name()
70        message = "Attribute '{0}' can not be used together with {1} in {2}".format(
71            attribute_name,
72            ", ".join("'{0}'".format(value) for value in attributes_in_conflict),
73            module,
74        )
75
76        super(AttributeConflictError, self).__init__(message)
77
78
79class YAMLFormatError(JenkinsJobsException):
80    pass
81
82
83class JJBConfigException(JenkinsJobsException):
84    pass
85