__init__.py 6.04 KB
Newer Older
Yannick Roehlly's avatar
Yannick Roehlly committed
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2012, 2013 Centre de données Astrophysiques de Marseille
3
# Licensed under the CeCILL-v2 licence - see Licence_CeCILL_V2-en.txt
Yannick Roehlly's avatar
Yannick Roehlly committed
4
# Author: Yannick Roehlly
Yannick Roehlly's avatar
Yannick Roehlly committed
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
import inspect
from importlib import import_module


def complete_parameters(given_parameters, parameter_list):
    """Complete the given parameter list with the default values

    Complete the given_parameters dictionary with missing parameters that have
    a default value in the parameter_list. If a parameter from parameter_list
    have no default value and is not present in given_parameters, raises an
    error. If a parameter is present in given_parameters and not in
    parameter_list, an exception is also raised.
    Returns an ordered dictionary with the same key order as the parameter
    list.

    Parameters
    ----------
24
    given_parameters: dictionary
25
        Parameter dictionary used to configure the module.
26
    parameter_list: dictionary
27
28
29
30
        Parameter list from the module.

    Returns
    -------
31
    parameters: dict
32
33
34
35
36
37
38
39
40
41
        Ordered dictionary combining the given parameters with the default
        values for the missing ones.

    Raises
    ------
    KeyError when the given parameters are different from the expected ones.

    """
    # Complete the given parameters with default values when needed.
    for key in parameter_list:
Médéric Boquien's avatar
Médéric Boquien committed
42
        if (key not in given_parameters) and (
43
44
45
46
                parameter_list[key][2] is not None):
            given_parameters[key] = parameter_list[key][2]
    # Check parameter consistency between the parameter list and the given
    # parameters.
Yannick Roehlly's avatar
Yannick Roehlly committed
47
48
49
    if not set(given_parameters) == set(parameter_list):
        missing_parameters = (set(parameter_list) - set(given_parameters))
        unexpected_parameters = (set(given_parameters) - set(parameter_list))
50
51
52
53
54
55
56
57
58
59
60
61
62
        message = ""
        if missing_parameters:
            message += ("Missing parameters: " +
                        ", ".join(missing_parameters) +
                        ". ")
        if unexpected_parameters:
            message += ("Unexpected parameters: " +
                        ", ".join(unexpected_parameters) +
                        ". ")
        raise KeyError("The parameters passed are different from the "
                       "expected one. " + message)

    # We want the result to be ordered as the parameter_list of the module is.
63
    result = dict()
Yannick Roehlly's avatar
Yannick Roehlly committed
64
    for key in parameter_list:
65
66
67
68
69
        result[key] = given_parameters[key]

    return result


70
class CreationModule(object):
71
72
73
    """Abstract class, the pCigale SED creation modules are based on.
    """

74
    # parameter_list is a dictionary containing all the parameters
75
76
77
78
79
    # used by the module. Each parameter name is associate to a tuple
    # (variable type, description [string], default value). Each module must
    # define its parameter list, unless it does not use any parameter. Using
    # None means that there is no description or default value. If None should
    # be the default value, use the 'None' string instead.
80
    parameter_list = dict()
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

    # comments is the text that is used to comment the module section in
    # the configuration file. For instance, it can be used to give special
    # instructions for the configuration.
    comments = ""

    def __init__(self, name=None, blank=False, **kwargs):
        """Instantiate a SED creation module

        A name can be given to the module. This can be useful when a same
        module is used several times with different parameters in the SED
        creation process.

        The module parameters must be passed as keyword parameters. If a
        parameter is not given but exists in the parameter_list with a default
        value, this value is used. If a parameter is missing or if an
        unexpected parameter is given, an error will be raised.

        Parameters
        ----------
101
        name: string
102
            Name of the module.
103
        blank: boolean
104
105
106
107
108
109
110
            If true, return a non-parametrised module that will be used only
            to query the module parameter list.

        The module parameters must be given as keyword parameters.

        Raises
        ------
111
        KeyError: when not all the needed parameters are given or when an
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
                   unexpected parameter is given.

        """
        # If a name is not given, we take if from the file in which the
        # module class is coded.
        self.name = name or os.path.basename(inspect.getfile(self))[:4]

        if not blank:
            # Parameters given in constructor.
            parameters = kwargs

            # Complete the parameter dictionary and "export" it to the module
            self.parameters = complete_parameters(parameters,
                                                  self.parameter_list)

            # Run the initialisation code specific to the module.
            self._init_code()

    def _init_code(self):
        """Initialisation code specific to the module.

        For instance, a module taking data in the database can use this method
        to do so, only one time when the module instantiates.

        """
        pass

    def process(self, sed):
        """Process a SED object with the module

        The SED object is updated during the process, one must take care of
        copying it before, if needed.

        Parameters
        ----------
147
        sed: pcigale.sed.SED object
148
149
150
151
152
153
154
155
156
157

        """
        raise NotImplementedError()


def get_module(name, **kwargs):
    """Get a SED creation module from its name

    Parameters
    ----------
158
    module_name: string
159
160
        The name of the module we want to get the class. This name can be
        prefixed by anything using a dot, then the part before the dot is
161
162
        used to determine the module to load (e.g. 'dl2014.1' will return
        the 'dl2014' module).
163
164
165
166
167
168
169

    Returns
    -------
    a pcigale.creation_modules.Module instance
    """

    try:
170
        module = import_module("." + name, 'pcigale.creation_modules')
171
172
173
174
        return module.Module(name=name, **kwargs)
    except ImportError:
        print('Module ' + module_name + ' does not exists!')
        raise