1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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
|
#
# Copyright (c) 2009 Testrepository Contributors
#
# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
# license at the users choice. A copy of both licenses are available in the
# project source as Apache-2.0 and BSD. You may not use this file except in
# compliance with one of these two licences.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# license you chose for the specific language governing permissions and
# limitations under that license.
"""In testrepository a UI is an interface to a 'user' (which may be a machine).
The testrepository.ui.cli module contains a command line interface, and the
module testrepository.ui.model contains a purely object based implementation
which is used for testing testrepository.
See AbstractUI for details on what UI classes should do and are responsible
for.
"""
class AbstractUI(object):
"""The base class for UI objects, this providers helpers and the interface.
A UI object is responsible for brokering interactions with a particular
user environment (e.g. the command line). These interactions can take
several forms:
- reading bulk data
- gathering data
- emitting progress or activity data - hints as to the programs execution.
- providing notices about actions taken
- showing the result of some query (including errors)
All of these things are done in a structured fashion. See the methods
iter_streams, query_user, progress, notice and result.
UI objects are generally expected to be used once, with a fresh one
created for each command executed.
:ivar cmd: The command that is running using this UI object.
:ivar here: The location that command is being run in. This may be a local
path or a URL. This is only guaranteed to be set after set_command is
called, as some UI's need to do option processing to determine its
value.
:ivar options: The options for this ui, containing both global and command
specific options.
"""
def _check_cmd(self):
"""Check that cmd is valid. This method is meant to be overridden.
:return: True if the cmd is valid - if options and args match up with
the ones supplied to the UI, and so on.
"""
def iter_streams(self, stream_type):
"""Iterate over all the streams of type stream_type.
Implementors of UI should implement _iter_streams which is called after
argument checking is performed.
:param stream_type: A simple string such as 'subunit' which matches
one of the stream types defined for the cmd object this UI is
being used with.
:return: A generator of stream objects. stream objects have a read
method and a close method which behave as for file objects.
"""
for stream_spec in self.cmd.input_streams:
if '*' in stream_spec or '?' in stream_spec or '+' in stream_spec:
found = stream_type == stream_spec[:-1]
else:
found = stream_type == stream_spec
if found:
return self._iter_streams(stream_type)
raise KeyError(stream_type)
def _iter_streams(self, stream_type):
"""Helper for iter_streams which subclasses should implement."""
raise NotImplementedError(self._iter_streams)
def output_rest(self, rest_string):
"""Show rest_string - a ReST document.
This is typically used as the entire output for command help or
documentation.
:param rest_string: A ReST source to display.
"""
raise NotImplementedError(self.output_rest)
def output_results(self, suite_or_test):
"""Show suite_or_test to the user by 'running' it.
This expects the run to be fast/cheap.
:param suite_or_test: A suite or test to show to the user. This should
obey the 'TestCase' protocol - it should have a method run(result)
that causes all the tests contained in the object to be handed to
the result object.
"""
raise NotImplementedError(self.output_results)
def output_stream(self, stream):
"""Show a byte stream to the user.
This is not currently typed, but in future a MIME type may be
permitted.
:param stream: A file like object that can be read from. The UI will
not close the file.
"""
raise NotImplementedError(self.output_results)
def output_table(self, table):
"""Show a table to the user.
:param table: an iterable of rows. The first row is used for column
headings, and every row needs the same number of cells.
e.g. output_table([('name', 'age'), ('robert', 1234)])
"""
raise NotImplementedError(self.output_table)
def output_values(self, values):
"""Show values to the user.
:param values: An iterable of (label, value).
"""
raise NotImplementedError(self.output_values)
def set_command(self, cmd):
"""Inform the UI what command it is running.
This is used to gather command line arguments, or prepare dialogs and
otherwise ensure that the information the command has declared it needs
will be available. The default implementation simply sets self.cmd to
cmd.
:param cmd: A testrepository.commands.Command.
"""
self.cmd = cmd
return self._check_cmd()
|