1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """C{expand [POSITION]}
19
20 Receives a stream of sequences as input. If C{POSITION} is omitted, then
21 each item of the sequence is generated as a separate 1-tuple in the
22 output stream.
23
24 B{Example}: If the input contains these sequences::
25
26 ('a', 'b')
27 ('c', 'd')
28
29 then C{expand} generates this output::
30 ('a',)
31 ('b',)
32 ('c',)
33 ('d',)
34
35 If C{POSITION} is specified, then each input sequence is used to generate
36 zero or more output sequences. In each output sequence, the item at the
37 selected position is replaced by one component of the selected object.
38
39 The types that can be expanded are C{list}, C{tuple}, C{generator},
40 and C{osh.file.File}. Expansion of a C{osh.file.File}
41 yields each line of the named file.
42
43 B{Example}: If the input contains these sequences::
44
45 ('a', [1, 2, 3], 'x')
46 ('b', [4, 5], 'y')
47 ('c', [], 'z')
48
49 then C{expand 1} generates this output::
50
51 ('a', 1, 'x')
52 ('a', 2, 'x')
53 ('a', 3, 'x')
54 ('b', 4, 'y')
55 ('b', 5, 'y')
56
57 Note that an empty nested sequence results in no output, (as for
58 C{('c', [], 'z')}.)
59 """
60
61 import types
62
63 import osh.core
64 import osh.file
65
66
69
70
72 """Flattens an input sequence by generating output sequences in which an interior element
73 is expanded. If C{position} is omitted, then each element of the input sequence is generated
74 as a separate 1-tuples. If C{position} is specified, then the item at the given position
75 is expanded. If the element being expanded is a string, then the string is interpreted
76 as a filename, and the expansion yields each line of the file in turn.
77 """
78 args = []
79 if position is not None:
80 args.append(position)
81 return _Expand().process_args(*args)
82
84
85 _expander = None
86
87
88
89
92
93
94
95
98
100 args = self.args()
101 position = args.next_int()
102 if position is not None and args.has_next():
103 self.usage()
104 if position is None:
105 self._expander = _SequenceExpander(self)
106 else:
107 self._expander = _ComponentExpander(self, position)
108
110 self._expander.expand(sequence)
111
113
114 _command = None
115
118
121
122 - def contents(self, object):
123 contents_generator = self._expand_as_file(object)
124 if not contents_generator:
125 contents_generator = self._expand_as_sequence(object)
126 if not contents_generator:
127 raise _NotExpandableException(object)
128 return contents_generator
129
132
134 if (isinstance(object, tuple) or
135 isinstance(object, list) or
136 isinstance(object, types.GeneratorType)):
137 return self._expand_sequence(object)
138 else:
139 return None
140
142 if isinstance(f, osh.file.File):
143 filename = f.abspath
144 else:
145 filename = f
146 file = open(filename, 'r')
147 eof = False
148 while not eof:
149 line = file.readline()
150 if line:
151 if line.endswith('\n'):
152 line = line[:-1]
153 yield line
154 else:
155 eof = True
156 file.close()
157
159 for object in sequence:
160 yield object
161
163
166
168 for object in self.contents(sequence):
169 self._command.send(object)
170
172
173
174 if ((isinstance(object, tuple) or isinstance(object, list)) and len(object) == 1):
175 object = object[0]
176 if isinstance(object, osh.file.File):
177 return self._expand_file(object)
178 else:
179 return None
180
182
183 _position = None
184
188
190 pre = sequence[:self._position]
191 if self._position == -1:
192 post = tuple()
193 else:
194 post = sequence[(self._position + 1):]
195 contents = self.contents(sequence[self._position])
196 for object in contents:
197 output = pre + (object,) + post
198 self._command.send(output)
199
201
202 if isinstance(sequence, osh.file.File):
203 return self._expand_file(sequence)
204 else:
205 return None
206
208
209 _object = None
210
212 self._object = object
213
215 return 'Object of type %s cannot be expanded: %s' % (type(self._object), self._object)
216