source: pyutilib.workflow/trunk/pyutilib/workflow/connections.py @ 1794

Revision 1794, 6.6 KB checked in by wehart, 4 years ago (diff)

Resolving back-portability issues for Python 2.4

Line 
1#  _________________________________________________________________________
2#
3#  PyUtilib: A Python utility library.
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  _________________________________________________________________________
9
10__all__ = ['Connection', 'UnknownConnection', 'DirectConnection']
11
12# TODO: output and input connections may have different properties.  How do we
13#       reconcile this behavior...???  It doesn't work to have them share the same
14#       connection object.
15
16class Connection(object):
17
18    def __init__(self, from_task=None, to_task=None, optional=False):
19        # TODO: clarify semantics for optional inputs and outputs
20        #   1. Create an error if a required input is connected to an optional output
21        #   2. Validate that non-optional inputs/outputs have a value other than None
22        import task
23        if not from_task is None:
24           self.from_task = from_task
25        else:
26           self.from_task = task.NoTask
27        self.to_task = set()
28        if not to_task is None:  #pragma:nocover
29            # This is not currently exercised.
30            # I am raising an error until we know when/how this code is needed
31            raise ValueError, "Setting a to_task in a Connection is not currently supported"
32            if isinstance(to_task, task.Task):
33                self.to_task.add(to_task)
34            else:
35                for t in to_task:
36                    self.to_task.add(t)
37
38    def get_value(self):
39        raise ValueError, "There is no value to get in an abstract Connection object!"  #pragma:nocover
40
41    def set_value(self, value):
42        raise ValueError, "There is no value to set in an abstract Connection object!"  #pragma:nocover
43   
44    def __repr__(self):
45        return str(self)
46
47    def __str__(self):
48        return "%s: from=(%s) to=(%s)" % (str(self.__class__.__name__), str(self.from_task), str(self.to_task))
49
50    def pprint(self):
51        print str(self)
52
53
54class UnknownConnection(Connection):
55
56    def __init__(self, from_task=None, to_task=None, optional=False):
57        Connection.__init__(self, from_task=from_task, to_task=to_task, optional=optional)
58
59    def get_value(self):
60        raise ValueError, "There is no value to get in an abstract Connection object!"  #pragma:nocover
61
62    def set_value(self, value):
63        raise ValueError, "There is no value to set in an abstract Connection object!"  #pragma:nocover
64   
65
66class DirectConnection(Connection):
67
68    def __init__(self, value=None, from_task=None, to_task=None, optional=False):
69        Connection.__init__(self, from_task=from_task, to_task=to_task, optional=optional)
70        self.set_value(value)
71
72    def get_value(self):
73        return self.value
74
75    def set_value(self, value):
76        self.value = value
77
78    def pprint(self):
79        print str(self)+" Value: "+str(self.value)
80
81
82class Connections(dict):
83
84    def __init__(self, task):
85        self._name_='Connections'
86        self._task = task
87        self._inputs=False
88        self._outputs=False
89
90    def set_name(self, name):
91        self._name_ = name
92
93    def declare(self, name, optional=False):
94        # TODO: use optional specification
95        if self._inputs:
96            setattr(self, name, DirectConnection(optional=optional))
97        else:
98            setattr(self, name, DirectConnection(from_task=self._task))
99        return getattr(self, name)
100
101    def __setitem__(self, name, val):
102        self.__setattr__(name,val)
103
104    def __getitem__(self, name):
105        return self.__getattr__(name)
106
107    def __setattr__(self, name, val):
108        #if not name in ('_task'):
109           #print "XXX",self.task.name if not self.task is None else "NONE",name,val
110        if name[0] == '_':
111            #dict.__setitem__(self, name, val)
112            self.__dict__[name] = val
113            return
114        #if not self._declaration and name[0] != '_' and not self._outputs:
115            #print self._declaration
116            #raise ValueError, "Cannot set attribute values.  Connection object '%s' is not configured for outputs." % self._name_
117        if name in ('inputs','outputs'):
118            raise ValueError, "Cannot set attribute value with name '%s'" % name
119        if not isinstance(val, Connection):
120            val = DirectConnection(value=val)
121            #raise ValueError, "Cannot set a Connections attribute to a value that is not a subclass of Connection"
122        if self._inputs:
123            val.to_task.add(self._task)
124        else:
125            val.from_task = self._task
126        dict.__setitem__(self, name, val)
127        self.__dict__[name] = val
128
129    def __getattr__(self, name):
130        try:
131            return dict.__getitem__(self, name)
132        except:
133            if name[0] == '_':
134                raise AttributeError, "Unknown attribute '%s'" % name
135
136    def __repr__(self):
137        attrs = sorted("%s = %r" % (k, v) for k, v in self.__dict__.iteritems() if not k.startswith("_"))
138        return "%s(%s)" % (self.__class__.__name__, ", ".join(attrs))
139
140    def __str__(self, nesting = 1, indent='', print_name=True):
141        attrs = []
142        if not print_name:
143            nesting -= 1    #pragma:nocover
144        indentation = indent+"    " * nesting
145        for k, v in self.__dict__.iteritems():
146            if not k.startswith("_"):
147                text = [indentation, k, " = "]
148                text.append(repr(v))
149                attrs.append("".join(text))
150        attrs.sort()
151        if print_name:
152            attrs.insert(0, indent+self._name_ + ":")
153        if self._inputs:
154            attrs.append("Mode:  inputs")
155        if self._outputs:
156            attrs.append("Mode:  outputs")
157        if not self._task is None:
158            attrs.append("Owner: "+str(self._task))
159        return "\n".join(attrs)
160
161
162
163class InputConnections(Connections):
164
165    def __init__(self, task):
166        Connections.__init__(self, task)
167        self._inputs=True
168
169
170class OutputConnections(Connections):
171
172    def __init__(self, task):
173        Connections.__init__(self, task)
174        self._outputs=True
175
176
177# TODO: this doesn't really work, since we're setting the attribute for In/Out
178# connections with a class instance.  Should this simply map to specifying
179# values in both the inputs and outputs section????
180class InOutConnections(Connections):
181
182    def __init__(self, task):
183        Connections.__init__(self, task)
184        self._inputs=True
185        self._outputs=True
186
Note: See TracBrowser for help on using the repository browser.